Compare commits

...
270 Commits
Author SHA1 Message Date
Eugene Yurtsev 18a2a2a832 x 2025-12-09 16:24:45 -05:00
Eugene Yurtsev 5ae0aff522 x 2025-12-09 16:24:38 -05:00
Eugene Yurtsev b7d068677c x 2025-12-09 11:28:15 -05:00
Eugene Yurtsev 706f3e981e x 2025-12-08 22:35:50 -05:00
Eugene Yurtsev 344ab65351 checkpoint sqlite 2025-12-08 21:24:00 -05:00
94698c8a34 feat: custom encryption at rest (#6482)
**Description:** 
This PR adds the Python SDK types necessary for langgraph platform users
to inject their own custom encryption-at-rest functions. See [docs
PR](https://github.com/langchain-ai/docs/pull/1715) for more details.

note: this PR adds a starlette dev dependency so that custom encryption
can access BaseUser information.

**Issue:**
required for LSD-172 

**Dependencies:**
- [depended upon by associated langgraph-api
changes](https://github.com/langchain-ai/langgraph-api/pull/1773)(this
PR must merge before that one)
- [docs PR](https://github.com/langchain-ai/docs/pull/1715)

**TODO:**
- [x] move docs to docs repo
- [x] bump package versions before merge

---------

Signed-off-by: Connor Braa <cwlbraa@langchain.dev>
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-06 00:10:17 +00:00
Mason DaughertyandGitHub 7d557cb865 chore: fix links for docs (#6538) 2025-12-05 23:09:41 +00:00
William FHandGitHub f211fadc2b release(sdk-py): Configure loopback client (#6536)
Will defer defaulting to deferred registration until a later date.
2025-12-05 11:56:40 -08:00
William FHandGitHub 024468c5dd chore: Bump lockfile (#6537) 2025-12-05 11:16:19 -08:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
7f08a6dafd chore(deps): bump js-yaml from 4.1.0 to 4.1.1 in /docs/_scripts/js_translation/codeblocks (#6452)
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.1.0 to 4.1.1.
<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.1.1] - 2025-11-12</h2>
<h3>Security</h3>
<ul>
<li>Fix prototype pollution issue in yaml merge (&lt;&lt;)
operator.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/nodeca/js-yaml/commit/cc482e775913e6625137572a3712d2826170e53a"><code>cc482e7</code></a>
4.1.1 released</li>
<li><a
href="https://github.com/nodeca/js-yaml/commit/50968b862e75866ef90e626572fe0b2f97b55f9f"><code>50968b8</code></a>
dist rebuild</li>
<li><a
href="https://github.com/nodeca/js-yaml/commit/d092d866031751cb27c12d93f3e2470ad74d678b"><code>d092d86</code></a>
lint fix</li>
<li><a
href="https://github.com/nodeca/js-yaml/commit/383665ff4248ec2192d1274e934462bb30426879"><code>383665f</code></a>
fix prototype pollution in merge (&lt;&lt;)</li>
<li><a
href="https://github.com/nodeca/js-yaml/commit/0d3ca7a27b03a6c974790a30a89e456007d62976"><code>0d3ca7a</code></a>
README.md: HTTP =&gt; HTTPS (<a
href="https://redirect.github.com/nodeca/js-yaml/issues/678">#678</a>)</li>
<li><a
href="https://github.com/nodeca/js-yaml/commit/49baadd52af887d2991e2c39a6639baa56d6c71b"><code>49baadd</code></a>
doc: 'empty' style option for !!null</li>
<li><a
href="https://github.com/nodeca/js-yaml/commit/ba3460eb9d3e4478edcbc29edabe17c2157fc9ce"><code>ba3460e</code></a>
Fix demo link (<a
href="https://redirect.github.com/nodeca/js-yaml/issues/618">#618</a>)</li>
<li>See full diff in <a
href="https://github.com/nodeca/js-yaml/compare/4.1.0...4.1.1">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.0&new-version=4.1.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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-12-02 19:54:26 +00:00
William FHandGitHub 76203e2c20 chore: Sync langgraph.json schema (#6530) 2025-12-02 19:52:06 +00:00
b6cc022861 fix(checkpoint): InMemorySaver context managers should return self in… (#6529)
h/t to @lexi-k for openening. merged here to check/fix CI

Co-authored-by: lexi-k <69981673+lexi-k@users.noreply.github.com>
2025-12-02 11:47:41 -08:00
Mason DaughertyandGitHub 02bb7a436a chore: remove erroneous release title prefix (#6528) 2025-12-02 13:45:43 -05:00
Hunter LovellandGitHub 43d21e9c7d chore(ci): disable redirects build hook (#6527) 2025-12-02 08:43:57 -05:00
William FHandGitHub 55ed7d4b49 feat: Include pagination in assistants search response (#6526) 2025-12-01 20:18:26 -08:00
William FHandGitHub 2b78bf3bad fix: docstring for serializer protocol (#6525) 2025-12-01 18:14:12 +00:00
Mason DaughertyandGitHub 630bd9ab95 fix: release name should be same as package name (#6503) 2025-11-25 19:02:44 -05:00
William FHandGitHub b945b1f21e release(langgraph): 1.0.4 (#6502)
This patch release includes a couple of small fixes and improvements,
such as:
- Include interrupt information in the values stream mode (no longer
rely solely on the updates stream mode):
https://github.com/langchain-ai/langgraph/pull/6475
- Omit thread_id from configurable to allow using context for stateful
runs via RemoteGraph:
https://github.com/langchain-ai/langgraph/pull/6497
2025-11-25 20:27:49 +00:00
William FHandGitHub 4cb108ccd9 release(sdk-py): 0.2.11 (#6501) 2025-11-25 19:17:40 +00:00
Josh RogersandGitHub 23d78c2817 feat(sdk-py): add sentinel to skip auto loading api key on sdk client create (#6500)
**Description:** There are times a user might want to create the client,
but conditionally set the API key. For example, consider a complex auth
situation where the system has user callers using jwts and system
callers using API keys. This allows explicitly disabling the
auto-loading behavior of API keys in the client today, so no key is set.
**Issue:** N/A
**Dependencies:** None
**Twitter handle:** N/A
2025-11-25 11:10:56 -08:00
William FHandGitHub f8c1a323cc chore(sdk-py): Improve type-hinting of inputs (#6480) 2025-11-24 18:29:03 -08:00
William FHandGitHub b7e329cf0a chore: pop thread ID from configurable fields in remote graph (#6497)
Otherwise, you cannot use `context` with stateful runs, because the
server throws if you provide both configurable and context in a single
call (due to ambiguous parameters)
2025-11-24 16:09:08 -08:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
3f49249e72 chore(deps): bump actions/checkout from 5 to 6 (#6490)
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to
6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update README to include Node.js 24 support details and requirements
by <a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2248">actions/checkout#2248</a></li>
<li>Persist creds to a separate file by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2286">actions/checkout#2286</a></li>
<li>v6-beta by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2298">actions/checkout#2298</a></li>
<li>update readme/changelog for v6 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2311">actions/checkout#2311</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v5.0.0...v6.0.0">https://github.com/actions/checkout/compare/v5.0.0...v6.0.0</a></p>
<h2>v6-beta</h2>
<h2>What's Changed</h2>
<p>Updated persist-credentials to store the credentials under
<code>$RUNNER_TEMP</code> instead of directly in the local git
config.</p>
<p>This requires a minimum Actions Runner version of <a
href="https://github.com/actions/runner/releases/tag/v2.329.0">v2.329.0</a>
to access the persisted credentials for <a
href="https://docs.github.com/en/actions/tutorials/use-containerized-services/create-a-docker-container-action">Docker
container action</a> scenarios.</p>
<h2>v5.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Port v6 cleanup to v5 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2301">actions/checkout#2301</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v5...v5.0.1">https://github.com/actions/checkout/compare/v5...v5.0.1</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>V6.0.0</h2>
<ul>
<li>Persist creds to a separate file by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2286">actions/checkout#2286</a></li>
<li>Update README to include Node.js 24 support details and requirements
by <a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2248">actions/checkout#2248</a></li>
</ul>
<h2>V5.0.1</h2>
<ul>
<li>Port v6 cleanup to v5 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2301">actions/checkout#2301</a></li>
</ul>
<h2>V5.0.0</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
</ul>
<h2>V4.3.1</h2>
<ul>
<li>Port v6 cleanup to v4 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2305">actions/checkout#2305</a></li>
</ul>
<h2>V4.3.0</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<h2>v4.2.2</h2>
<ul>
<li><code>url-helper.ts</code> now leverages well-known environment
variables by <a href="https://github.com/jww3"><code>@​jww3</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li>
<li>Expand unit test coverage for <code>isGhes</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li>
</ul>
<h2>v4.2.1</h2>
<ul>
<li>Check out other refs/* by commit if provided, fall back to ref by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li>
</ul>
<h2>v4.2.0</h2>
<ul>
<li>Add Ref and Commit outputs by <a
href="https://github.com/lucacome"><code>@​lucacome</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1180">actions/checkout#1180</a></li>
<li>Dependency updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>- <a
href="https://redirect.github.com/actions/checkout/pull/1777">actions/checkout#1777</a>,
<a
href="https://redirect.github.com/actions/checkout/pull/1872">actions/checkout#1872</a></li>
</ul>
<h2>v4.1.7</h2>
<ul>
<li>Bump the minor-npm-dependencies group across 1 directory with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1739">actions/checkout#1739</a></li>
<li>Bump actions/checkout from 3 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1697">actions/checkout#1697</a></li>
<li>Check out other refs/* by commit by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1774">actions/checkout#1774</a></li>
<li>Pin actions/checkout's own workflows to a known, good, stable
version. by <a href="https://github.com/jww3"><code>@​jww3</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1776">actions/checkout#1776</a></li>
</ul>
<h2>v4.1.6</h2>
<ul>
<li>Check platform to set archive extension appropriately by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1732">actions/checkout#1732</a></li>
</ul>
<h2>v4.1.5</h2>
<ul>
<li>Update NPM dependencies by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1703">actions/checkout#1703</a></li>
<li>Bump github/codeql-action from 2 to 3 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1694">actions/checkout#1694</a></li>
<li>Bump actions/setup-node from 1 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1696">actions/checkout#1696</a></li>
<li>Bump actions/upload-artifact from 2 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1695">actions/checkout#1695</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/checkout/commit/1af3b93b6815bc44a9784bd300feb67ff0d1eeb3"><code>1af3b93</code></a>
update readme/changelog for v6 (<a
href="https://redirect.github.com/actions/checkout/issues/2311">#2311</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/71cf2267d89c5cb81562390fa70a37fa40b1305e"><code>71cf226</code></a>
v6-beta (<a
href="https://redirect.github.com/actions/checkout/issues/2298">#2298</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/069c6959146423d11cd0184e6accf28f9d45f06e"><code>069c695</code></a>
Persist creds to a separate file (<a
href="https://redirect.github.com/actions/checkout/issues/2286">#2286</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493"><code>ff7abcd</code></a>
Update README to include Node.js 24 support details and requirements (<a
href="https://redirect.github.com/actions/checkout/issues/2248">#2248</a>)</li>
<li>See full diff in <a
href="https://github.com/actions/checkout/compare/v5...v6">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=5&new-version=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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 13:41:21 -08:00
Andrew NguonlyandGitHub 78910dade0 chore: Bump version of sdk-py to 0.2.10 (#6496)
**Description:** Updating `sdk-py` version for release.
2025-11-24 12:27:16 -08:00
Andrew NguonlyandGitHub 33fbd1bb9c feat(sdk-py): Add name parameter to Assistants search API (#6483)
**Description:** The Agent Server API now supports searching for
assistants by name.
2025-11-24 10:58:54 -08:00
Mason DaughertyandGitHub d45f52ab0c chore: clean up some refs (#6487) 2025-11-23 02:13:30 -05:00
William FHandGitHub ed07d4a5d4 chore(sdk-py): Add more type checking. (#6479) 2025-11-20 17:40:23 -08:00
Caspar BroekhuizenandGitHub 2284a54b64 fix: interrupt stream mode values (#6475)
This PR improves the consistency of interrupt streaming. 

- when streaming with stream_mode values, the stream chunk now contains
the entire state alongside the interrupt:

```python
class State(TypedDict):
    robot_input: str
# at this point in time robot_input is already set to  "beep boop i am a robot"
app.stream(..., stream_mode="values")
# before
{"__interrupt__": (Interrupt(value="interrupt",))}}
# after
{"robot_input": "beep boop i am a robot", "__interrupt__": (Interrupt(value="interrupt"))}
```

- when streaming with stream_mode=["values", "updates"], interrupts are
surfaced in both an update stream chunk and the value stream chunk, when
previously we keep interrupt in values only if we request values mode
only

```python
class State(TypedDict):
    robot_input: str
# at this point in time robot_input is already set to  "beep boop i am a robot"
app.stream(..., stream_mode=["values", "updates"])
# before (interrupt would only emit on update chunk, there would be no values chunk)
("updates", {"__interrupt__": (Interrupt(value="interrupt",))}})
# after
("updates", {"__interrupt__": (Interrupt(value="interrupt",))}})
("values", {"robot_input": "beep boop i am a robot", "__interrupt__": (Interrupt(value="interrupt"))})
```

For housekeeping: this PR improves on this revert:
https://github.com/langchain-ai/langgraph/pull/6141
2025-11-20 14:23:09 -08:00
Sydney RunkleandGitHub f8006b2fee release: langgraph-prebuilt 1.0.5 (#6473) 2025-11-20 11:45:19 -05:00
Sydney RunkleandGitHub 2164b7daa3 fix: refactor injection logic to respect function signatures (#6468)
## overview

The main purpose of this is to respect tool signatures that request
injected args (like `ToolRuntime`) even when the explicitly specified
`args_schema` does not.

Ex in the following example, we should still inject `runtime` despite
its absence in `ArgsSchema`

```py
class ArgsSchema(BaseModel):
    some_arg: int = Field(...)

@tool(args_schema=ArgsSchema)
def my_tool(some_arg: int, runtime: ToolRuntime): ...
```

This is accompanied by
https://github.com/langchain-ai/langchain/pull/34051 which has tests
that pass w/ this change. This tests injection w/ `create_agent` (more
end to end than tests added in
https://github.com/langchain-ai/langchain/pull/33999.

This unblocks the injection of `ToolRuntime` into MCP tools which is
exciting bc that exposes tool call id and state, which we previously
were unable to do.

## other benefits

* Cleaner code structure w/ more helpful docs about injected args.
* Nice perf boost, we're no longer inspecting the annotations of a
tool's schema 3 different times to detect store, state, and runtime
injections.

## additional notes

1. I could see a world where we want more of this logic to reside on the
tools themselves, but tools don't now about LG specific injection types
(like `ToolRuntime`, hence having this logic here for now).
2. We could separately add validation for the case where something is
specified in `args_schema` and not in the function signature (probably
at the tool level though).
2025-11-20 11:37:54 -05:00
Sydney RunkleandGitHub 6d20a0b9c7 fix: deprecate setattr on ToolCallRequest (#6462)
* one alternative considered was setting `frozen=True` on the dataclass,
but this is breaking, so a deprecation is a nicer approach
2025-11-19 13:12:11 -05:00
William FHandGitHub df8becd5cf refactor: separate prepare_push_* functions (#6450)
Extract two common cases from the big switch statement of
`prepare_single_task` since it's a tad more composable.

All this does is shift/extract code to separate functions
2025-11-14 16:13:03 -08:00
Lauren Hirata SinghandGitHub 056ba91a71 chore(docs): add more redirects + catchall (#6442) 2025-11-13 14:49:40 -05:00
Sydney RunkleandGitHub 02300de24c fix: dep warnings in prebuilt (#6443) 2025-11-13 13:59:34 -05:00
Sydney RunkleandGitHub ac16bdb795 release: prebuilt 1.0.3 (#6441) 2025-11-13 13:38:24 -05:00
Caspar BroekhuizenandGitHub 0d4ac836e3 chore: langgraph patch release (#6429) 2025-11-10 09:37:35 -08:00
Lauren Hirata SinghandGitHub 201c8015ea chore(docs): Update links in notebook_hooks.py for deployment (#6428) 2025-11-10 09:51:05 -05:00
Mason DaughertyandGitHub cf3e8252f5 feat(docs): warn that StateGraph is a builder class (#6417) 2025-11-07 21:09:15 -05:00
Mason DaughertyandGitHub 7a5e3c1e79 fix(docs): PartialState rendering in MkDocs (#6416)
The carat chars were not rendering without code style formatting
2025-11-07 21:08:01 -05:00
Mason DaughertyandGitHub 218c60717e fix(docs): synchronize invoke and ainvoke docstrings (#6415)
Similar to #6414
2025-11-07 20:44:33 -05:00
Mason DaughertyandGitHub 28b9f578b0 fix(docs): synchronize stream and astream docstrings (#6414)
`stream` and `astream` docstrings listed different available
`stream_mode` options.

Both methods support the same seven stream modes as defined in
`StreamMode`

Fixed for consistency
2025-11-07 20:44:25 -05:00
le-codeur-rapideandGitHub bef76b791c docs(langgraph): Fix docstring code examples of task function (#6410)
Hi all,
I found out that the sync and async code examples of the `task` function
in `libs/langgraph/langgraph/func/__init__.py` have a typo:
```
    Example: Sync Task
        ```python
        from langgraph.func import entrypoint, task


        @task
        def add_one(a: int) -> int:
            return a + 1


        @entrypoint()
        def add_one(numbers: list[int]) -> list[int]:
            futures = [add_one(n) for n in numbers]
            results = [f.result() for f in futures]
            return results


        # Call the entrypoint
        add_one.invoke([1, 2, 3])  # Returns [2, 3, 4]
        ```
```

Both task and entrypoint functions have the same name which gives an
error.

This is a small PR to fix this
2025-11-07 16:01:19 -05:00
a1b34efdb0 fix(checkpoint-postgres): ensure vector extension is created only if not exists (#6154)
Thank you for contributing to LangGraph! Follow these steps to mark your
pull request as ready for review. **If any of these steps are not
completed, your PR will not be considered for review.**

- [x] **PR title**: Follows the format: {TYPE}({SCOPE}): {DESCRIPTION}
  - Examples:
    - feat(core): add multi-tenant support
    - fix(cli): resolve flag parsing error
    - docs(openai): update API usage examples
  - Allowed `{TYPE}` values:
- feat, fix, docs, style, refactor, perf, test, build, ci, chore,
revert, release
  - Allowed `{SCOPE}` values (optional):
- langgraph, docs, cli, checkpoint, checkpoint-postgres,
checkpoint-sqlite, prebuilt, scheduler-kafka, sdk-py
- Once you've written the title, please delete this checklist item; do
not include it in the PR.

- **Description:** Azure Postgres SQL server has a limitation when doing
create extension vector is not exists, even though it manually created
before on a schema.
- **Issue:** Even though `CREATE EXTENSION vector` is executed manually
before, the permission issue arises. Putting it in an if else block
solves the issue and its not a breaking change.
```
Because vector isn't a trusted extension, only members of "azure_pg_admin" are allowed to use CREATE EXTENSION vector
HINT: to learn how to allow an extension or see the list of allowed extensions, please refer to https://go.microsoft.com/fwlink/?linkid=2301063
```

Co-authored-by: Josh Rogers <josh@langchain.dev>
2025-11-07 11:42:15 -05:00
André MenezesandGitHub 7ab5788f25 fix(langgraph): Unexpected behavior for stream_mode sequences that are not lists (#6354)
## Issue
The `stream_mode` argument type includes `Sequence`, but it doesn't
correctly support non-list sequences. On the other hand, the
`print_mode` argument works as expected.

### Example
```python
from langgraph.pregel.main import Pregel

pregel = Pregel(nodes={}, channels=None, input_channels=[], output_channels=[], auto_validate=False)
stream_modes, *_ = pregel._defaults(
    config={"recursion_limit": 1},
    stream_mode=("values", "messages"),
    print_mode=("values"),
    output_keys=None,
    interrupt_before=None,
    interrupt_after=None,
    durability=None,
)
print(stream_modes) # Expected `{'values', 'messages'}`, got `{('values', 'messages'), 'values'}`
```
2025-11-07 08:01:25 -05:00
Cole MurrayandGitHub b0a1029d55 fix(checkpoint-postgres): Replace f-string SQL formatting with parameterized queries in migration statements (#6328)
## Summary

Replace f-string SQL formatting with parameterized queries to prevent
potential SQL injection in checkpoint migration code.

## Changes

Updated the migration version tracking INSERT statements in all
checkpoint saver classes to use parameterized queries instead of
f-string formatting:

- `PostgresSaver`
(libs/checkpoint-postgres/langgraph/checkpoint/postgres/__init__.py:100)
- `AsyncPostgresSaver`
(libs/checkpoint-postgres/langgraph/checkpoint/postgres/aio.py:104-106)
- `ShallowPostgresSaver`
(libs/checkpoint-postgres/langgraph/checkpoint/postgres/shallow.py:255)
- `AsyncShallowPostgresSaver`
(libs/checkpoint-postgres/langgraph/checkpoint/postgres/shallow.py:617-619)

**Before (vulnerable to SQL injection):**
```python
cur.execute(f"INSERT INTO checkpoint_migrations (v) VALUES ({v})")
```

**After (using parameterized query):**
```python
cur.execute("INSERT INTO checkpoint_migrations (v) VALUES (%s)", (v,))
```

## Risk Assessment

The practical risk is low since `v` is an integer loop variable
controlled by the codebase. However, using string formatting in SQL
queries is a well-known anti-pattern that can lead to SQL injection
vulnerabilities, especially if the code is later refactored or copied to
other contexts.

## Testing

-  All 216 tests passing on PostgreSQL 15 and 16
-  Linting and type checking passing
-  No functional changes to behavior
2025-11-07 08:00:10 -05:00
Mason DaughertyandGitHub c2ef3f3fd3 fix: remove SDK inline links (#6307)
these were broken; remove for now.
2025-11-07 07:56:00 -05:00
Michael LiandGitHub d455bd841d fix: fix previoius edge cases such as 0 (#6379)
Thank you for contributing to LangGraph! Follow these steps to mark your
pull request as ready for review. **If any of these steps are not
completed, your PR will not be considered for review.**

- [x] **PR title**: Follows the format: {TYPE}({SCOPE}): {DESCRIPTION}
  - Examples:
    - feat(core): add multi-tenant support
    - fix(cli): resolve flag parsing error
    - docs(openai): update API usage examples
  - Allowed `{TYPE}` values:
- feat, fix, docs, style, refactor, perf, test, build, ci, chore,
revert, release
  - Allowed `{SCOPE}` values (optional):
- langgraph, docs, cli, checkpoint, checkpoint-postgres,
checkpoint-sqlite, prebuilt, scheduler-kafka, sdk-py
- Once you've written the title, please delete this checklist item; do
not include it in the PR.

- [x] **PR message**: ***Delete this entire checklist*** and replace
with
- **Description:** a description of the change. Include a [closing
keyword](https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword)
if applicable.
  - **Issue:** the issue # it fixes, if applicable
  - **Dependencies:** any dependencies required for this change
- **Twitter handle:** if your PR gets announced, and you'd like a
mention, we'll gladly shout you out!

- [x] **Add tests and docs**: If you're adding a new integration, you
must include:
1. A test for the integration, preferably unit tests that do not rely on
network access,
2. An example notebook showing its use. It lives in
`docs/docs/integrations` directory.

- [x] **Lint and test**: Run `make format`, `make lint` and `make test`
from the root of the package(s) you've modified. We will not consider a
PR unless these three are passing in CI. See [contribution
guidelines](https://github.com/langchain-ai/langgraph/blob/main/CONTRIBUTING.md)
for more.

Additional guidelines:

- Make sure optional dependencies are imported within a function.
- Please do not add dependencies to `pyproject.toml` files (even
optional ones) unless they are **required** for unit tests.
- Most PRs should not touch more than one package.
- Changes should be backwards compatible.
2025-11-07 07:54:22 -05:00
Pedro Enrique Agurto CastilloandGitHub 69a09adef6 fix(langgraph): export REMOVE_ALL_MESSAGES in __all__ to fix linting (#6375)
`REMOVE_ALL_MESSAGES` is a public constant used with `RemoveMessage` to
clear all messages from the state:

```python
from langchain_core.messages import RemoveMessage
from langgraph.graph.message import REMOVE_ALL_MESSAGES

# Clear all messages
[RemoveMessage(id=REMOVE_ALL_MESSAGES)]
```

However, it is not exported in __all__, causing:

Linting errors in IDEs (PyCharm)
no-member warnings from Pylint
Confusion for users

This PR:

Adds REMOVE_ALL_MESSAGES to __all__
Adds inline docstring with usage example

No runtime behavior changes — only improves IDE support and API clarity.

Thank you for contributing to LangGraph! Follow these steps to mark your
pull request as ready for review. **If any of these steps are not
completed, your PR will not be considered for review.**

---
Local verification:
```bash
# Before
from langgraph.graph.message import REMOVE_ALL_MESSAGES  # Pylint: no-member

# After: no error
```
CI Note: This is a pure export/docs fix. `make lint` and `make test`
pass unchanged.
2025-11-07 07:52:27 -05:00
Kavya GoyalandGitHub 35aa98b110 fix(sdk-py): use correct f-string representation when loading error (#6388)
Thank you for contributing to LangGraph! Follow these steps to mark your
pull request as ready for review. **If any of these steps are not
completed, your PR will not be considered for review.**


## Description
- Fixed a bug in `libs/sdk-py/langgraph_sdk/auth/__init__.py` where the
error message for an already-set authentication handler did not properly
render the handler value.
- Updated the error string from a static `{self._authenticate_handler}`
to a correctly interpolated f-string.

```python
"Authentication handler already set as {self._authenticate_handler}."
```

```python
f"Authentication handler already set as {self._authenticate_handler}."
```

- Error messages now correctly display the actual handler instance,
improving debugging clarity.



- **Issue:** Fixes https://github.com/langchain-ai/langgraph/issues/6387
  - **Dependencies:** -
  - **Twitter handle:** -

- [x] **Add tests and docs**: If you're adding a new integration, you
must include:
1. A test for the integration, preferably unit tests that do not rely on
network access,
2. An example notebook showing its use. It lives in
`docs/docs/integrations` directory.

- [ ] **Lint and test**: Run `make format`, `make lint` and `make test`
from the root of the package(s) you've modified. We will not consider a
PR unless these three are passing in CI. See [contribution
guidelines](https://github.com/langchain-ai/langgraph/blob/main/CONTRIBUTING.md)
for more.

Additional guidelines:

- Make sure optional dependencies are imported within a function.
- Please do not add dependencies to `pyproject.toml` files (even
optional ones) unless they are **required** for unit tests.
- Most PRs should not touch more than one package.
- Changes should be backwards compatible.
2025-11-07 07:51:35 -05:00
Mason DaughertyandGitHub 0f83d9fafe style: update docstrings to reference StateGraph (#6308)
nit
2025-11-07 07:47:29 -05:00
Logan RosenandGitHub 52d66df92c docs(langgraph): update streaming guide links (#6314)
Updating links to the LangGraph streaming guide to point to the new
documentation website for 1.0.
2025-11-07 07:46:48 -05:00
Mason DaughertyandGitHub 4ec92f9fb1 chore: add pyproject.toml links (#6364) 2025-11-07 07:43:51 -05:00
inhunandGitHub 2b72953064 docs: add license files for checkpoint-sqlite and checkpoint-postgres (#6392)
In this PR:

- Add missing LICENSE files for checkpoint-sqlite and
checkpoint-postgres libraries.

Both libraries specify the MIT License in their pyproject.toml files,
but the actual LICENSE files were missing.
This update adds the corresponding LICENSE files to ensure proper
license documentation and compliance.
2025-11-07 07:39:06 -05:00
le-codeur-rapideandGitHub 232014e8ef docs(langgraph): Fix typo in docstring of PregelLoop.tick (#6407)
This is a very small PR to correct a typo in the docstring of the
`PregelLoop.tick()` method.
```python
  def tick(self) -> bool:
      """Execute a single iteration of the Pregel loop.

      Args:
          input_keys: The key(s) to read input from.

      Returns:
          True if more iterations are needed.
      """
```

Corrected to :
```python
  def tick(self) -> bool:
      """Execute a single iteration of the Pregel loop.

      Returns:
          True if more iterations are needed.
      """
```

The docstring was written in #2946 when the signature of tick was
```python
    def tick(
        self,
        *,
        input_keys: Union[str, Sequence[str]],
    ) -> bool:
```
but  it was simplified to 
```python
def tick(self) -> bool:
```
in #5080
2025-11-07 07:38:16 -05:00
Josh RogersandGitHub 9fd3dfc542 chore(checkpoint-postgres): bump to 3.0.1 (#6402)
**Description:** Bumping the checkpoint-postgres package to version
3.0.1 to release an update to migrations
(https://github.com/langchain-ai/langgraph/pull/6400).
**Issue:** N/A
**Dependencies:** N/A
**Twitter handle:** N/A
2025-11-06 11:14:02 -05:00
Josh RogersandGitHub ff38f75594 fix(checkpoint-postgres): make async PG checkpoint migration idempotent (#6400)
- **Description:** The final migration for the postgres checkpointer is
not currently idempotent. That presents problems when migrating from one
checkpointer to another or if migrations otherwise get applied twice.
This makes the final migration idempotent to avoid this problem.
- **Issue:** N/A
- **Dependencies:** N/A
- **Twitter handle:** N/A
2025-11-06 09:49:51 -05:00
Kathryn MayandGitHub bbdd007341 chore(docs): Update redirects for langgraph server to agent server rename (#6399)
Renaming LangGraph Server to Agent Server, this updates the redirects
from the old site to the new site's renamed files.
PR also includes some hosting --> platform setup redirects
2025-11-05 11:21:09 -05:00
Caspar BroekhuizenandGitHub 3c75e414e5 fix(langgraph): do not apply pending writes when updating state (#6389)
PR #6195 fixed `bulk_update_state` to populate `task.result` by calling
`prepare_next_tasks` to discover task IDs. Before #6195,
prepare_next_tasks was gated by the condition `CONFIG_KEY_CHECKPOINT_ID
not in config[CONF]` - so it only ran if we were resuming from an empty
checkpoint. This check was removed in order to properly populate task
results. However, the removal of this check inadvertently applied
pending writes during manual state updates which caused issues when
forking:

- When you fork from a checkpoint by calling `update_state(config,
new_values, as_node="mynode")`, pending writes from the original
execution were being applied
- This caused stale data to leak into forked threads (eg. old tool call
results appearing in forked execution)

Changes

Removed pending writes application from `bulk_update_state` and
`abulk_update_state`:
- Still call `prepare_next_tasks` to discover task IDs, but skip the
code that applies null writes and regular pending writes

Tests

- Added `test_fork_does_not_apply_pending_writes` for sync and async
which verifies forking doesn't include stale pending writes from
original execution
2025-11-04 14:38:40 -08:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
575401c78c chore(deps): bump hono from 4.9.7 to 4.10.3 in /docs/_scripts/js_translation/codeblocks (#6339)
Bumps [hono](https://github.com/honojs/hono) from 4.9.7 to 4.10.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/honojs/hono/releases">hono's
releases</a>.</em></p>
<blockquote>
<h2>v4.10.3</h2>
<h2>Securiy Fix</h2>
<p>A security issue in the CORS middleware has been fixed. In some
cases, a request header could affect the Vary response header. Please
update to the latest version if you are using the CORS middleware.</p>
<h2>What's Changed</h2>
<ul>
<li>fix(aws-lambda): serve microsoft office files as binary in lambda
handler by <a
href="https://github.com/matthiasfeist"><code>@​matthiasfeist</code></a>
in <a
href="https://redirect.github.com/honojs/hono/pull/4469">honojs/hono#4469</a></li>
<li>fix(request-id): validation accepts <code>=</code> by <a
href="https://github.com/ryuapp"><code>@​ryuapp</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/4478">honojs/hono#4478</a></li>
<li>refactor(jwt): reduce the size of the code generated by minification
by <a href="https://github.com/usualoma"><code>@​usualoma</code></a> in
<a
href="https://redirect.github.com/honojs/hono/pull/4480">honojs/hono#4480</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/matthiasfeist"><code>@​matthiasfeist</code></a>
made their first contribution in <a
href="https://redirect.github.com/honojs/hono/pull/4469">honojs/hono#4469</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/honojs/hono/compare/v4.10.2...v4.10.3">https://github.com/honojs/hono/compare/v4.10.2...v4.10.3</a></p>
<h2>v4.10.2</h2>
<h2>Security hardening improvement</h2>
<p>If you are using JWT middleware, please read the following and
consider applying the configuration.</p>
<h3>Improper Authorization in Hono (JWT Audience Validation)</h3>
<p>Hono’s JWT authentication middleware did not validate the aud
(Audience) claim by default. As a result, applications using the
middleware without an explicit audience check could accept tokens
intended for other audiences, leading to potential cross-service access
(token mix-up).</p>
<p>The issue is addressed by adding a new <code>verification.aud</code>
configuration option to allow RFC 7519–compliant audience validation.
This change is classified as a security hardening improvement, but the
lack of validation can still be considered a vulnerability in
deployments that rely on default JWT verification.</p>
<h3>Recommended secure configuration</h3>
<p>You can enable RFC 7519–compliant audience validation using the new
<code>verification.aud</code> option:</p>
<pre lang="ts"><code>import { Hono } from 'hono'
import { jwt } from 'hono/jwt'
<p>const app = new Hono()</p>
<p>app.use(<br />
'/api/*',<br />
jwt({<br />
secret: 'my-secret',<br />
verification: {<br />
// Require this API to only accept tokens with aud = 'service-a'<br />
aud: 'service-a',<br />
},<br />
})<br />
)<br />
</code></pre></p>
<h2>What's Changed</h2>
<ul>
<li>tests: Fix test case of handlers without a path by <a
href="https://github.com/IAmSSH"><code>@​IAmSSH</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/4472">honojs/hono#4472</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/honojs/hono/commit/fcefd50c65144eda31e2bc6752c81904171d9629"><code>fcefd50</code></a>
4.10.3</li>
<li><a
href="https://github.com/honojs/hono/commit/95ae4d372119cddba32e4935d2bbc6f4e2768dab"><code>95ae4d3</code></a>
refactor(jwt): reduce the size of the code generated by minification (<a
href="https://redirect.github.com/honojs/hono/issues/4480">#4480</a>)</li>
<li><a
href="https://github.com/honojs/hono/commit/d9b8b4b73b4f997994f2764013207365fe711282"><code>d9b8b4b</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/honojs/hono/commit/52161170e83298fc3d13312bfceba3992916bfa2"><code>5216117</code></a>
fix(request-id): validation accepts <code>=</code> (<a
href="https://redirect.github.com/honojs/hono/issues/4478">#4478</a>)</li>
<li><a
href="https://github.com/honojs/hono/commit/253ec2857a083595e52a446694923645084e9ecd"><code>253ec28</code></a>
fix(aws-lambda): serve microsoft office files as binary in lambda
handler (<a
href="https://redirect.github.com/honojs/hono/issues/4">#4</a>...</li>
<li><a
href="https://github.com/honojs/hono/commit/0c6455dc10db6428257bdd601eca559247e27de6"><code>0c6455d</code></a>
4.10.2</li>
<li><a
href="https://github.com/honojs/hono/commit/45ba3bf9e3dff8e4bd85d6b47d4b71c8d6c66bef"><code>45ba3bf</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/honojs/hono/commit/4cbad8b3e2a67d77849710ec400d9de020c435fd"><code>4cbad8b</code></a>
tests: Fix test case of handlers without a path (<a
href="https://redirect.github.com/honojs/hono/issues/4472">#4472</a>)</li>
<li><a
href="https://github.com/honojs/hono/commit/db764c2f1d8a2905d66c78c41aa47e47d3a4165d"><code>db764c2</code></a>
4.10.1</li>
<li><a
href="https://github.com/honojs/hono/commit/8774bf9a59278a9593d5e91cc85543d5a4bb518c"><code>8774bf9</code></a>
fix(types): cannot <code>.use</code> non-return mw from
<code>createMiddleware</code> (<a
href="https://redirect.github.com/honojs/hono/issues/4465">#4465</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/honojs/hono/compare/v4.9.7...v4.10.3">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=hono&package-manager=npm_and_yarn&previous-version=4.9.7&new-version=4.10.3)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-11-04 13:52:15 -08:00
William FHandGitHub 092c9ecde6 chore: update ormsgpack minbound and add OPT_REPLACE_SURROGATES (#6395)
This lets the default `msgpack` serialization mode handle more cases
where user data contains invalid unicode.
2025-11-04 13:51:34 -08:00
William FHandGitHub 8336686e89 release(cli): 0.4.7 expand api bounds (#6390)
Fixes #6380
2025-11-03 23:47:05 +00:00
Parker J. RuleandGitHub 8b080a091e fix(checkpoint): update checkpoint interface specification in README (#6386)
This syncs the checkpoint interface specification with the base class
(`BaseCheckpointSaver`) in
`langgraph/libs/checkpoint/langgraph/checkpoint/base /__init__.py`.
2025-11-03 21:44:41 +00:00
Asamu DavidandGitHub 1157ec77b4 fix(cli): add buildkit syntax directiive, update tests (#6385)
**Description:** Adds the syntax directive to generated dockerfile for
langgraph builds if we have additional contexts
**Issue:** fixes issue with python monorepo builds failing
**Dependencies:** N/A
2025-11-03 18:13:19 +00:00
William FHandGitHub a10a66cbd1 chore: Update cli config schema (#6372) 2025-11-01 09:50:46 -07:00
Kathryn MayandGitHub ae525fb74f docs: Update hosting page name redirect to platform setup (#6371) 2025-10-31 14:12:59 -04:00
Mason DaughertyandGitHub a6dde39be7 chore: style fixes for refs (#6365) 2025-10-30 17:59:40 -04:00
Sydney RunkleandGitHub c1661dd07f chore: bump prebuilt dep for lg (#6361) 2025-10-29 18:34:28 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2d848ffddd chore(deps): bump actions/upload-artifact from 4 to 5 (#6347)
Bumps
[actions/upload-artifact](https://github.com/actions/upload-artifact)
from 4 to 5.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/upload-artifact/releases">actions/upload-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<p><strong>BREAKING CHANGE:</strong> this update supports Node
<code>v24.x</code>. This is not a breaking change per-se but we're
treating it as such.</p>
<ul>
<li>Update README.md by <a
href="https://github.com/GhadimiR"><code>@​GhadimiR</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/681">actions/upload-artifact#681</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/712">actions/upload-artifact#712</a></li>
<li>Readme: spell out the first use of GHES by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/upload-artifact/pull/727">actions/upload-artifact#727</a></li>
<li>Update GHES guidance to include reference to Node 20 version by <a
href="https://github.com/patrikpolyak"><code>@​patrikpolyak</code></a>
in <a
href="https://redirect.github.com/actions/upload-artifact/pull/725">actions/upload-artifact#725</a></li>
<li>Bump <code>@actions/artifact</code> to <code>v4.0.0</code></li>
<li>Prepare <code>v5.0.0</code> by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/upload-artifact/pull/734">actions/upload-artifact#734</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/GhadimiR"><code>@​GhadimiR</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/upload-artifact/pull/681">actions/upload-artifact#681</a></li>
<li><a href="https://github.com/nebuk89"><code>@​nebuk89</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/upload-artifact/pull/712">actions/upload-artifact#712</a></li>
<li><a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/upload-artifact/pull/727">actions/upload-artifact#727</a></li>
<li><a
href="https://github.com/patrikpolyak"><code>@​patrikpolyak</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/upload-artifact/pull/725">actions/upload-artifact#725</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-artifact/compare/v4...v5.0.0">https://github.com/actions/upload-artifact/compare/v4...v5.0.0</a></p>
<h2>v4.6.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Update to use artifact 2.3.2 package &amp; prepare for new
upload-artifact release by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/685">actions/upload-artifact#685</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/upload-artifact/pull/685">actions/upload-artifact#685</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-artifact/compare/v4...v4.6.2">https://github.com/actions/upload-artifact/compare/v4...v4.6.2</a></p>
<h2>v4.6.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Update to use artifact 2.2.2 package by <a
href="https://github.com/yacaovsnc"><code>@​yacaovsnc</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/673">actions/upload-artifact#673</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-artifact/compare/v4...v4.6.1">https://github.com/actions/upload-artifact/compare/v4...v4.6.1</a></p>
<h2>v4.6.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Expose env vars to control concurrency and timeout by <a
href="https://github.com/yacaovsnc"><code>@​yacaovsnc</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/662">actions/upload-artifact#662</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-artifact/compare/v4...v4.6.0">https://github.com/actions/upload-artifact/compare/v4...v4.6.0</a></p>
<h2>v4.5.0</h2>
<h2>What's Changed</h2>
<ul>
<li>fix: deprecated <code>Node.js</code> version in action by <a
href="https://github.com/hamirmahal"><code>@​hamirmahal</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/578">actions/upload-artifact#578</a></li>
<li>Add new <code>artifact-digest</code> output by <a
href="https://github.com/bdehamer"><code>@​bdehamer</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/656">actions/upload-artifact#656</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/hamirmahal"><code>@​hamirmahal</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/upload-artifact/pull/578">actions/upload-artifact#578</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/upload-artifact/commit/330a01c490aca151604b8cf639adc76d48f6c5d4"><code>330a01c</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/734">#734</a>
from actions/danwkennedy/prepare-5.0.0</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/03f282445299bbefc96171af272a984663b63a26"><code>03f2824</code></a>
Update <code>github.dep.yml</code></li>
<li><a
href="https://github.com/actions/upload-artifact/commit/905a1ecb5915b264cbc519e4eb415b5d82916018"><code>905a1ec</code></a>
Prepare <code>v5.0.0</code></li>
<li><a
href="https://github.com/actions/upload-artifact/commit/2d9f9cdfa99fedaddba68e9b5b5c281eca26cc63"><code>2d9f9cd</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/725">#725</a>
from patrikpolyak/patch-1</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/9687587dec67f2a8bc69104e183d311c42af6d6f"><code>9687587</code></a>
Merge branch 'main' into patch-1</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/2848b2cda0e5190984587ec6bb1f36730ca78d50"><code>2848b2c</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/727">#727</a>
from danwkennedy/patch-1</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/9b511775fd9ce8c5710b38eea671f856de0e70a7"><code>9b51177</code></a>
Spell out the first use of GHES</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/cd231ca1eda77976a84805c4194a1954f56b0727"><code>cd231ca</code></a>
Update GHES guidance to include reference to Node 20 version</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/de65e23aa2b7e23d713bb51fbfcb6d502f8667d8"><code>de65e23</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/712">#712</a>
from actions/nebuk89-patch-1</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/8747d8cd7632611ad6060b528f3e0f654c98869c"><code>8747d8c</code></a>
Update README.md</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/upload-artifact/compare/v4...v5">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/upload-artifact&package-manager=github_actions&previous-version=4&new-version=5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-29 10:03:28 -07:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
4c8d965710 chore(deps): bump actions/download-artifact from 5 to 6 (#6348)
Bumps
[actions/download-artifact](https://github.com/actions/download-artifact)
from 5 to 6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/download-artifact/releases">actions/download-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.0</h2>
<h2>What's Changed</h2>
<p><strong>BREAKING CHANGE:</strong> this update supports Node
<code>v24.x</code>. This is not a breaking change per-se but we're
treating it as such.</p>
<ul>
<li>Update README for download-artifact v5 changes by <a
href="https://github.com/yacaovsnc"><code>@​yacaovsnc</code></a> in <a
href="https://redirect.github.com/actions/download-artifact/pull/417">actions/download-artifact#417</a></li>
<li>Update README with artifact extraction details by <a
href="https://github.com/yacaovsnc"><code>@​yacaovsnc</code></a> in <a
href="https://redirect.github.com/actions/download-artifact/pull/424">actions/download-artifact#424</a></li>
<li>Readme: spell out the first use of GHES by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/download-artifact/pull/431">actions/download-artifact#431</a></li>
<li>Bump <code>@actions/artifact</code> to <code>v4.0.0</code></li>
<li>Prepare <code>v6.0.0</code> by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/download-artifact/pull/438">actions/download-artifact#438</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/download-artifact/pull/431">actions/download-artifact#431</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/download-artifact/compare/v5...v6.0.0">https://github.com/actions/download-artifact/compare/v5...v6.0.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/download-artifact/commit/018cc2cf5baa6db3ef3c5f8a56943fffe632ef53"><code>018cc2c</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/438">#438</a>
from actions/danwkennedy/prepare-6.0.0</li>
<li><a
href="https://github.com/actions/download-artifact/commit/815651c680ffe1c95719d0ed08aba1a2f9d5c177"><code>815651c</code></a>
Revert &quot;Remove <code>github.dep.yml</code>&quot;</li>
<li><a
href="https://github.com/actions/download-artifact/commit/bb3a066a8babc8ed7b3e4218896c548fe34e7115"><code>bb3a066</code></a>
Remove <code>github.dep.yml</code></li>
<li><a
href="https://github.com/actions/download-artifact/commit/fa1ce46bbd11b8387539af12741055a76dfdf804"><code>fa1ce46</code></a>
Prepare <code>v6.0.0</code></li>
<li><a
href="https://github.com/actions/download-artifact/commit/4a24838f3d5601fd639834081e118c2995d51e1c"><code>4a24838</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/431">#431</a>
from danwkennedy/patch-1</li>
<li><a
href="https://github.com/actions/download-artifact/commit/5e3251c4ff5a32e4cf8dd4adaee0e692365237ae"><code>5e3251c</code></a>
Readme: spell out the first use of GHES</li>
<li><a
href="https://github.com/actions/download-artifact/commit/abefc31eafcfbdf6c5336127c1346fdae79ff41c"><code>abefc31</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/424">#424</a>
from actions/yacaovsnc/update_readme</li>
<li><a
href="https://github.com/actions/download-artifact/commit/ac43a6070aa7db8a41e756e7a2846221edca7027"><code>ac43a60</code></a>
Update README with artifact extraction details</li>
<li><a
href="https://github.com/actions/download-artifact/commit/de96f4613b77ec03b5cf633e7c350c32bd3c5660"><code>de96f46</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/417">#417</a>
from actions/yacaovsnc/update_readme</li>
<li><a
href="https://github.com/actions/download-artifact/commit/7993cb44e9052f2f08f9b828ae5ef3ecca7d2ac7"><code>7993cb4</code></a>
Remove migration guide for artifact download changes</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/download-artifact/compare/v5...v6">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/download-artifact&package-manager=github_actions&previous-version=5&new-version=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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-29 10:03:18 -07:00
Sydney RunkleandGitHub 4ac1c628ee chore: port tool node improvements back to langgraph (#6321)
namespace decisions

```
langgraph.prebuilt
  ├── ToolRuntime  # new
# all of the other stuff that was already there

langgraph.prebuilt.tool_node
  ├── ToolNode
  ├── ToolCallRequest  # new
  ├── ToolRuntime  # new
  ├── InjectedState
  ├── InjectedStore
  ├── ToolCallWrapper
  ├── AsyncToolCallWrapper
  ├── tools_condition
```
```
langchain.tools
  ├── ToolRuntime  # now from langgraph.prebuilt
  ├── InjectedState  # now from langgraph.prebuilt
  ├── InjectedStore  # now from langgraph.prebuilt
  ├── ToolException
  ├── tool
  ├── BaseTool
  ├── InjectedToolArg
  ├── InjectedToolCallId
```
2025-10-29 09:58:06 -07:00
Sydney RunkleandGitHub 41f8e61589 chore: bump core dep for prebuilt (#6323)
bumping core dependency for `langgraph-prebuilt` to `>1.0.0` so that we
can take advantage of internal utils that allow `ToolRuntime` injection.

We were previously bumping the version in lock step with prebuilt (prev
version was 0.3.67), so this pattern is in line with that.

Also updating snapshots accordingly:
* New mermaid syntax for a few graphs
* Removal of `examples` from `AIMessage`
2025-10-29 09:51:51 -07:00
Lauren Hirata SinghandGitHub 57a877279d chore(docs): Revert the revert "fix: rollback doc redirects" (add redirects) (#6353)
Reverts langchain-ai/langgraph#6301

This adds redirects back
2025-10-29 12:12:06 -04:00
Caspar BroekhuizenandGitHub d6dea53323 fix(langgraph): dont persist UntrackedValue (#6316)
UntrackedValue is a special channel type where the values in it are not
persisted to memory. Our v1 create_agent middleware used UntrackedValue
in middleware (e.g. ShellToolMiddleware) for some cool features like
temp files.

If a user has elected to use a checkpointer, we normally enforce that
the values they write to channels are serializable. However, this
doesn't make sense to enforce for UntrackedValues because the contract
is they're never written to checkpoint - so the user should not be
forced to make the contents of the channel serializable

However when using a checkpointer and durability sync/async, we found
that writes would still be persisted that contained UntrackedValue
contents in two forms:
a) UntrackedValue channel objects 
b) Send objects - in the state passed to another node

Patched this in put_writes by a) skipping persisting writes to
UntrackedValue channels altogether and b) popping all UntrackedValue kv
pairs nested within Send packets. We also need to sanitize in
_put_checkpoint which is called when durability=="exit".

Added a basic test for UntrackedValue in test_channel.py and added more
comprehensive tests using Send under some different scenarios in
test_pregel.py
2025-10-28 16:40:22 -07:00
Caspar BroekhuizenandGitHub 504e91ad5a feat(langgraph): add Overwrite to bypass reducer (#6286)
See https://github.com/langchain-ai/langgraph/pull/6277

Adds langgraph.types.Overwrite, a deterministic way to bypass a reducer.
When encountering a value wrapped with Overwrite,
BinaryOperatorAggregate overwrites the channel value.

<img width="227" height="329" alt="image"
src="https://github.com/user-attachments/assets/f2136117-9aa3-4246-863d-d5df0e7d1df1"
/>

If either node_b or node_c overwrite (but not both), then at END the
channel is equal to the value node_b or node_c wrote. Order of execution
doesn't matter because once an Overwrite value is encountered, regular
values are ignored (self.operator is not called for the rest of the
update)

If multiple nodes overwrite in the same superstep then
InvalidUpdateError is thrown

Usage
```python
from langgraph.types import Overwrite

def node_b(state:State):
    return {"messages": Overwrite(["b"])}
```
or
``` python
def node_b(state:State):
    return {"messages": {"__overwrite__": ["b"]}}
```
2025-10-27 11:31:35 -07:00
Mason DaughertyandGitHub 10abf2deb1 fix: replace python.langchain links with new docs.langchain (#6352) 2025-10-27 13:36:12 -04:00
Parker J. RuleandGitHub 5796ca9a0a fix(sdk-py): refine body param type (Auth.authenticate) (#6322)
Requests are not guaranteed to contain a body, and a request's body is
not guaranteed to be valid JSON. 

This updates the type signature for authentication handlers 
to account for these scenarios.
2025-10-22 17:35:15 +00:00
William FHandGitHub fca3e4513c release: Checkpointers 3.0 (#6313)
In this PR:

- Bump `langgraph-checkpoint` to 3.0
- Bump `langgraph-checkpoint-sqlite` to 3.0; Update
`langgraph-checkpoint` deps to >=3,<4
- Bump `langgraph-checkpoint-postgres` to 3.0; Update
`langgraph-checkpoint` max to <4 (keep prior min since the deprecated
functionality wasn't explicitly used)
- Bump `langgraph` to 1.0.1; update `langgraph-checkpoint` max bound to
4
- Bump `prebuilt` to 1.0.1; update `langgraph-checkpoint` max bound to 4
2025-10-20 11:31:55 -07:00
c5744f583b chore: Restrict "json" type deserialization (#6269)
- Rm untyped loads/dumps
- Restrict to an allow list

---------

Co-authored-by: Sydney Runkle <sydneymarierunkle@gmail.com>
2025-10-20 10:18:36 -07:00
Hunter LovellandGitHub d298b489b4 fix: rollback doc redirects (#6301) 2025-10-17 16:54:42 -04:00
Sydney RunkleandGitHub c4144bb48f release: langgraph + langgraph-prebuilt v1.0.0 (#6300) 2025-10-17 19:15:29 +00:00
Sydney RunkleandGitHub 2c3e380a35 feat: adding cursory Python 3.14 support (#6298)
* catching error thrown by asyncio
* using 2nd check for annotations given Pydantic 2.12 changes
* skipping tests for remote graph bc langgraph-api is dependent on
`jsonschema-rs`
* skipping tests w/ pydantic v1 models

```bash
hint: This usually indicates a problem with the package or the build environment.
  help: `jsonschema-rs` (v0.29.1) was included because `langgraph:dev` (v1.0.0rc1) depends on `langgraph-cli[inmem]` which
        depends on `langgraph-api` (v0.4.29) which depends on `jsonschema-rs`
```

not yet testing for free threaded python, that'll be much more involved!

ended up separating lint / testing deps during this process bc I was
getting a ton of not required deps while testing that were complicating
things :/
2025-10-17 08:26:52 -04:00
Lauren Hirata SinghandGitHub cf39fa5a91 fix(docs): fix catchall redirect (#6299) 2025-10-17 07:27:41 -04:00
Mason DaughertyandGitHub 7e666b58cd style: fixes for ref docs (#6297) 2025-10-16 20:58:16 -04:00
Asamu DavidandGitHub 3f400b38d1 fix(cli): install local deps in editable mode (#6294)
**Description** 

As part of this PR #6156, local deps are no longer installed in editable
mode. This change reverts that behaviour and ensures local packages are
installed in editable mode.

**Issue:** fixes #6288
2025-10-17 01:42:11 +01:00
Sydney RunkleandGitHub 6527df688c chore: release rcs for prebuilt + langgraph (#6296) 2025-10-17 00:35:56 +00:00
Sydney RunkleandGitHub aec841bd2a chore(prebuilt): un-deprecate tool node for now (#6295) 2025-10-16 20:27:24 -04:00
Sydney RunkleandGitHub 2d3121a17c chore: drop Python 3.9 (and syntax) (#6289)
* `strict=False` is the default, pyupgrade to min version 3.10 adds this
to be explicit w/ behavior
2025-10-16 20:17:46 -04:00
Lauren Hirata SinghandGitHub 06f9142419 chore(docs): Fix redirects (#6292) 2025-10-16 14:01:54 -04:00
Lauren Hirata SinghandGitHub a926450601 docs: Redirects for new docs (#5824)
This adds redirects to new Mintlify site and should be merged when old
LangGraph docs are deprecated (for v1)
2025-10-16 12:55:30 -04:00
abb96c0e2f chore(cli): re-word schema arguments (#6243)
Clean up config docstrings

---------

Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-10-16 12:28:09 +00:00
d9e3d83894 docs: style linting (#6260)
also fixes some links

---------

Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
Co-authored-by: ccurme <chester.curme@gmail.com>
Co-authored-by: Sydney Runkle <sydneymarierunkle@gmail.com>
Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com>
2025-10-16 11:25:50 +00:00
cedecd8ed6 chore(docs): Update OpenAPI spec from LangGraph API v0.4.42 (#6287)
This PR updates the OpenAPI specification with changes detected from the
LangGraph API server.

**Changes detected as of LangGraph API version 0.4.42**

This update was automatically generated by the sync workflow in the
langgraph-api repository.

Co-authored-by: hinthornw <hinthornw@users.noreply.github.com>
2025-10-16 07:15:51 -04:00
6bf9a7a4bc docs: relocate init args to __init__ (#6259)
Griffe expects parameter documentation to be in the method where
parameters are defined, not in the class docstring.

Class docstrings describe what the class does, while `__init__`
docstrings describe how to instantiate it with specific parameters.

---------

Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
Co-authored-by: ccurme <chester.curme@gmail.com>
Co-authored-by: Sydney Runkle <sydneymarierunkle@gmail.com>
Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com>
2025-10-16 07:11:42 -04:00
bce1dcfcd2 release(langgraph): v1 working branch (#6093)
Diff viewer for langgraph v1 alpha releases

---------

Co-authored-by: ccurme <chester.curme@gmail.com>
Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com>
Co-authored-by: Mason Daugherty <github@mdrxy.com>
Co-authored-by: Mason Daugherty <mason@langchain.dev>
2025-10-16 07:11:22 -04:00
Sam CrowderandGitHub 9b46cba1fb fix: rename away from LangGraph Platform (#6281)
some of these changes were obvious, and some were less obvious. In a few
spots, it felt like a judgement call if we should be saying LangSmith
Deployment of LangGraph Server. But hopefully either works.
2025-10-15 11:27:15 -07:00
Kathryn MayandGitHub a6dab889d1 docs: Update lgp home redirect to deployments (#6283) 2025-10-15 10:47:28 -04:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Eugene Yurtsev
7c6dbb3972 chore(deps): bump astral-sh/setup-uv from 6 to 7 (#6273)
Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6
to 7.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/setup-uv/releases">astral-sh/setup-uv's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.0 🌈 node24 and a lot of bugfixes</h2>
<h2>Changes</h2>
<p>This release comes with a load of bug fixes and a speed up. Because
of switching from node20 to node24 it is also a breaking change. If you
are running on GitHub hosted runners this will just work, if you are
using self-hosted runners make sure, that your runners are up to date.
If you followed the normal installation instructions your self-hosted
runner will keep itself updated.</p>
<p>This release also removes the deprecated input
<code>server-url</code> which was used to download uv releases from a
different server.
The <a
href="https://github.com/astral-sh/setup-uv?tab=readme-ov-file#manifest-file">manifest-file</a>
input supersedes that functionality by adding a flexible way to define
available versions and where they should be downloaded from.</p>
<h3>Fixes</h3>
<ul>
<li>The action now respects when the environment variable
<code>UV_CACHE_DIR</code> is already set and does not overwrite it. It
now also finds <a
href="https://docs.astral.sh/uv/reference/settings/#cache-dir">cache-dir</a>
settings in config files if you set them.</li>
<li>Some users encountered problems that <a
href="https://github.com/astral-sh/setup-uv?tab=readme-ov-file#disable-cache-pruning">cache
pruning</a> took forever because they had some <code>uv</code> processes
running in the background. Starting with uv version <code>0.8.24</code>
this action uses <code>uv cache prune --ci --force</code> to ignore the
running processes</li>
<li>If you just want to install uv but not have it available in path,
this action now respects <code>UV_NO_MODIFY_PATH</code></li>
<li>Some other actions also set the env var <code>UV_CACHE_DIR</code>.
This action can now deal with that but as this could lead to unwanted
behavior in some edgecases a warning is now displayed.</li>
</ul>
<h3>Improvements</h3>
<p>If you are using minimum version specifiers for the version of uv to
install for example</p>
<pre lang="toml"><code>[tool.uv]
required-version = &quot;&gt;=0.8.17&quot;
</code></pre>
<p>This action now detects that and directly uses the latest version.
Previously it would download all available releases from the uv repo
to determine the highest matching candidate for the version specifier,
which took much more time.</p>
<p>If you are using other specifiers like <code>0.8.x</code> this action
still needs to download all available releases because the specifier
defines an upper bound (not 0.9.0 or later) and &quot;latest&quot; would
possibly not satisfy that.</p>
<h2>🚨 Breaking changes</h2>
<ul>
<li>Use node24 instead of node20 <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/608">#608</a>)</li>
<li>Remove deprecated input server-url <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/607">#607</a>)</li>
</ul>
<h2>🐛 Bug fixes</h2>
<ul>
<li>Respect UV_CACHE_DIR and cache-dir <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/612">#612</a>)</li>
<li>Use --force when pruning cache <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/611">#611</a>)</li>
<li>Respect UV_NO_MODIFY_PATH <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/603">#603</a>)</li>
<li>Warn when <code>UV_CACHE_DIR</code> has changed <a
href="https://github.com/jamesbraza"><code>@​jamesbraza</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/601">#601</a>)</li>
</ul>
<h2>🚀 Enhancements</h2>
<ul>
<li>Shortcut to latest version for minimum version specifier <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/598">#598</a>)</li>
</ul>
<h2>🧰 Maintenance</h2>
<ul>
<li>Bump dependencies <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/613">#613</a>)</li>
<li>Fix test-uv-no-modify-path <a
href="https://github.com/eifinger"><code>@​eifinger</code></a> (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/604">#604</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/3259c6206f993105e3a61b142c2d97bf4b9ef83d"><code>3259c62</code></a>
Bump deps (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/633">#633</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/bf8e8ed895b7f686f85839659243f31a7df4a977"><code>bf8e8ed</code></a>
Split up documentation (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/632">#632</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/9c6b5e9fb575cac8e82bb437dd7fc25a094bd85d"><code>9c6b5e9</code></a>
Add resolution-strategy input to support oldest compatible version
selection ...</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/a5129e99f44f5d2ba22cdc54770745bd6f0d9c33"><code>a5129e9</code></a>
Add copilot-instructions.md (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/630">#630</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/d18bcc753ac29c1ed721aa4a812a90eb937852d6"><code>d18bcc7</code></a>
Add value of UV_PYTHON_INSTALL_DIR to path (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/628">#628</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/bd1f875aba1ebb6d38211b773b094ad1dcca58df"><code>bd1f875</code></a>
Set output venv when activate-environment is used (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/627">#627</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/1a91c3851df47749b241e3c5c696350957c93ff0"><code>1a91c38</code></a>
chore: update known checksums for 0.9.2 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/626">#626</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/c79f606987cb4a0f3d1a95a3e44bcebfb0a9b303"><code>c79f606</code></a>
chore: update known checksums for 0.9.1 (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/625">#625</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/e0249f159931b41f44fc8208c9b4cff085288cc9"><code>e0249f1</code></a>
Fall back to PR for updating known versions (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/623">#623</a>)</li>
<li><a
href="https://github.com/astral-sh/setup-uv/commit/6d2eb15b4979924f7be71aa06908c6211f80ac88"><code>6d2eb15</code></a>
Cache python installs (<a
href="https://redirect.github.com/astral-sh/setup-uv/issues/621">#621</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/setup-uv/compare/v6...v7">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=astral-sh/setup-uv&package-manager=github_actions&previous-version=6&new-version=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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
2025-10-14 10:55:27 -04:00
Kathryn MayandGitHub e08b8352a8 docs: Update old LDP site redirects to Platform docs merge (#6242)
This PR updates the redirects from the old LGP site to the new address
on the Mintlify site for the platform merge.
2025-10-14 10:23:19 -04:00
Sam CrowderandGitHub f7fe7c6698 fix: Revert "fix(cli): rename studio to debugger (#6246)" (#6261) 2025-10-09 23:35:36 +00:00
Caspar BroekhuizenandGitHub c2bc6ab8e9 chore(langgraph): bump langgraph version (#6257)
- Bump langgraph version to 0.6.10
2025-10-09 09:39:42 -07:00
Caspar BroekhuizenandGitHub 420550501f fix(langgraph): revert selective interrupt task scheduling (#6252)
Reverts langchain-ai/langgraph#6158
2025-10-08 12:34:01 -07:00
Sam CrowderandGitHub a0599139b8 fix(cli): rename studio to debugger (#6246)
begin process of renaming Studio to Debugger

keep --studio-url around for now as an option as well
2025-10-08 09:40:26 -07:00
Parker J. RuleandGitHub c2f359f708 chore(cli): bump to 0.4.3 (#6251)
Releases #6193 (and a few other minor changes).
2025-10-08 15:31:54 +00:00
Caspar BroekhuizenandGitHub 7f78a011fd chore(langgraph): bump version (#6245)
- Bump langgraph version from 0.6.8 to 0.6.9
2025-10-07 13:45:25 -07:00
Caspar BroekhuizenandGitHub 7d166bfb9f chore(checkpoint): bump patch version (#6244)
- Bump `langgraph-checkpoint` to 2.1.2
- Bump `langgraph-checkpoint-postgres` to 2.0.25 and raise
`langgraph-checkpoint` dep lower bound to 2.1.2
2025-10-07 10:41:24 -07:00
6cc8899818 fix(langgraph): selective interrupt task scheduling (#6158)
### Description

Prevents interrupt tasks from executing when the resume value has not
yet been specified.

Implemented for sync and async Pregel loop

If a task execution is skipped, the skipped interrupt is still included
in the graph result for consistency:
``` python
result = graph.invoke(...)
interrupts = result.get("__interrupt__", [])   # [interrupt_1, interrupt_2]

partial_result = graph.invoke(Command(resume=interrupt_1_resume_map), ...)
remaining_interrupts = partial_result.get("__interrupt__", [])  # [interrupt_2]
```

### Tests

- `test_interrupt_with_send_payloads`: test for a single resume map that
resumes all interrupts at once
- `test_interrupt_with_send_payloads_sequential_resume`: test for two
resume maps delivered in sequence
- `test_node_with_multiple_interrupts_requires_full_resume` test
optimization for multiple interrupts within a single node

Solves https://github.com/langchain-ai/langgraph/issues/6208

---------

Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
2025-10-06 13:11:52 -07:00
1ba96f49bf fix(checkpoint): handle metadata.writes when serializing old checkpoints with Jsonb (#6236)
Issue

Support for `Checkpoint.metadata.writes` was dropped in `langgraph`
v0.5.x.

In `langgraph-checkpoint-postgres` v2.0.23, metadata was serialized with
`BasePostgresSaver._dump_metadata` -> `JsonPlusSerializer.dumps` which
handles `pydantic.BaseModel`.

In v2.0.23, metadata is serialized with `psycopg.types.json.Jsonb`,
which raises `TypeError: Object of type AIMessage is not JSON
serializable` when trying to serialize `writes`.

Solution

- Add `BaseCheckpointSaver.get_serializable_checkpoint_metadata` which
pops the `writes` key.
- Log deprecation warning when strange version combinations are used 

Solves https://github.com/langchain-ai/langgraph/issues/5769

---------

Co-authored-by: Alex Kondratev <56111142+soapun@users.noreply.github.com>
2025-10-06 11:27:34 -07:00
Caspar BroekhuizenandGitHub b0958115c1 fix(langgraph): task result from stream mode debug / tasks should match format from get_state_history / get_state (#6233)
Overview

Python port of https://github.com/langchain-ai/langgraphjs/pull/1551

Introduces `map_task_result_writes` to standardize task result format
across `get_state_history` and `map_task_result_writes` response
structures.

Solves https://github.com/langchain-ai/langgraph/issues/6073
2025-10-03 09:06:58 -07:00
Mason DaughertyandGitHub 04fb14d3ae fix(langgraph): don't use rst code blocks in docstrings (#6231) 2025-10-01 00:08:07 +00:00
Mason DaughertyandGitHub efb0e8c176 docs(langgraph): standardize version-added admonitions (#6230) 2025-09-30 18:39:12 -04:00
Caspar BroekhuizenandGitHub 0584eaa5c4 fix(langgraph): fix supersteps not populating task.result field (#6195)
### Description

Fix `bulk_update_state` and `abulk_update_state` so history populates
`tasks[*].result` when creating state via supersteps.

There was a branch in these functions that I'm guessing was meant to be
triggered when a `StateUpdate.as_node` was the name of a real node (not
`"__input__"` or `"__copy__"`), but was never being triggered because of
a condition `CONFIG_KEY_CHECKPOINT_ID not in config[CONF]`:
```python
# apply pending writes, if not on specific checkpoint
if (
    CONFIG_KEY_CHECKPOINT_ID not in config[CONF]
    and saved is not None
    and saved.pending_writes
):
    next_tasks = prepare_next_tasks(...)
```

From what I can tell, in the bulk-update flow every superstep carries a
`checkpoint_id`, so the condition was always false. That skipped
`prepare_next_tasks(...)` and prevented us from discovering the task IDs
that we would need to attach the task result. So, I removed this check.

I also replaced the `pending_writes` check with a more lenient one (just
check it is not None to satisfy type checkers). I found that
`saved.pending_writes` was sometimes just `[]`, and in this case we
would skip `prepare_next_tasks(...)` and never attach the task result.

Now for each task discovered in `prepare_next_tasks(...)`, I collect the
task IDs and reuse them when running all writers of the chosen node
(applying the updates).

### Tests

- `test_supersteps_populate_task_results` for `PregelLoop` and
`AsyncPregelLoop`
 
These tests build a single node graph and compare history from two
threads: one uses `.invoke` and the other is build from supersteps. Both
tests fail on main and pass with this PR.

### Issue

Solves https://github.com/langchain-ai/langgraph/issues/6206
2025-09-30 12:52:59 -07:00
Caspar BroekhuizenandGitHub 0c73af5624 fix(langgraph): revert -- reuse cached writes on nested resume to prevent task re-execution (#6227)
Reverts langchain-ai/langgraph#6161
2025-09-30 11:28:41 -07:00
Isaac FranciscoandGitHub 9d1bb9d86c chore(checkpoint-postgres): bump version (#6222) 2025-09-30 07:41:59 -07:00
Kathryn MayandGitHub 7c69cb54a6 docs: Update redirects for studio obs consolidation (#6220)
Update the redirects from the old docs to page changes in the new docs,
namely consolidating all the observability studio guides onto one page.

Dependent on: https://github.com/langchain-ai/docs/pull/681
2025-09-29 15:18:40 -04:00
Kathryn MayandGitHub c2279cbe6f docs: Update redirects for consolidating studio content (#6219)
Contingent on this PR merging:
https://github.com/langchain-ai/docs/pull/679
2025-09-29 13:02:44 -04:00
Sydney RunkleandGitHub 3a024cff6d release(langgraph): 0.6.8 (#6215) 2025-09-29 09:16:43 +00:00
4a0b2fa0ef chore(deps): upgrade dependencies with uv lock --upgrade (#6211)
This PR updates the dependencies in all Python packages using `uv lock
--upgrade`.

This is an automated PR created by the UV Lock Upgrade workflow.

Co-authored-by: sydney-runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-09-29 09:07:51 +00:00
Sydney RunkleandGitHub 36179ab1d2 fix(langgraph): handle multiple annotations w/ BaseChannel detection (#6210)
This PR ensures that even if a type has multiple annotations, we can
still detect the `BaseChannel` subclasses attached.

```py
class State(TypedDict):
    # recognized as EphemeralValue(int)
    foo: Annotated[int, EphemeralValue]

    # now recognized as EphemeralValue(int)
    bar: Annotated[int, EphemeralValue, OtherMetadata]

    # now recognized as EphemeralValue(int)
    baz: Annotated[int, SomeMetadata, EphemeralValue, OtherMetadata]
```
2025-09-26 17:22:24 -04:00
Parker J. RuleandGitHub 20ddb2b8b4 fix(langgraph): CheckpointTask.state can be a StateSnapshot (#6201)
This adds `StateSnapshot` to the union type annotation of
`CheckpointTask.state`.

The annotation was previously incomplete: `map_debug_checkpoint()`
generates `CheckpointPayload` objects from `PregelTask` objects, and the
`state` field in `PregelTask` is of type `None | RunnableConfig |
StateSnapshot`.
2025-09-25 22:30:19 +00:00
Parker J. RuleandGitHub b0a25f2794 feat(cli): add flag in HttpConfig for auth on custom routes (#6193)
We currently only support auth on the default routes; we'd like to be
able to support it on all (non-meta/liveness probe) routes by default.
This is the first step in that direction.
2025-09-25 17:17:33 -04:00
Parker J. RuleandGitHub ea0aebaa2e chore(sdk-py): refine FilterType, add subset containment to $contains docs (#6200)
The `$contains` auth operator supports subset containment checks, but
this has previously been undocumented. This updates `FilterType` and its
associated docstring to reflect this support.
2025-09-25 15:58:35 -04:00
Mason DaughertyandGitHub 26c68aa528 docs: update README and scripts for improved clarity (#6197) 2025-09-25 17:31:27 +00:00
Mason DaughertyandGitHub 4101aebeea chore(langgraph): clean up ruff format config (#6188)
Each of the settings present are already defaults in the ruff config:

https://docs.astral.sh/ruff/settings/
2025-09-25 17:07:00 +00:00
Mason DaughertyandGitHub 90ac06deb6 style(langgraph): docstring code format pass (#6187) 2025-09-25 13:00:21 -04:00
Isaac FranciscoandGitHub 32d66d48eb chore(sdk-py): type errors nicely (#6173)
This PR types errors in a nicer way
2025-09-24 12:58:38 -04:00
Isaac FranciscoandGitHub d933d455ec fix(cli): change prerelease behavior (#6156)
respect users config, use uv defaults
2025-09-24 09:54:24 -07:00
c421afba65 chore(langgraph): adding author credit for non-ASCII text support (#6186)
Co-authored-by: dcdmm <dcdmm@users.noreply.github.com>
2025-09-24 09:05:11 -04:00
6139dacef9 fix(langgraph): cleanup orphaned waiter task in AsyncPregelLoop (#6167)
### Summary

This PR fixes an issue where `AsyncPregelLoop` could leave behind an
orphaned `stream.wait()` task, resulting in warnings like:

```
Task was destroyed but it is pending!
```

### Related Discussion
This PR is in response to:
[langchain-ai/langgraph#6163](https://github.com/langchain-ai/langgraph/discussions/6163)


### Problem

* In the async path, `get_waiter()` was creating a new `asyncio.Task`
via

  ```python
  aioloop.create_task(stream.wait())
  ```

  but never tracked or cleaned it up.
* On cancellation or shutdown, these tasks remained pending and produced
warnings.

### Solution

* Changed `get_waiter()` to:

  * Maintain a **single waiter task** (similar to the sync path).
  * Auto-clear the reference when the task finishes.
* Added `_cleanup_waiter()`:

* On exit, attempt to wake the waiter (`stream._count.release()` if
available).
* Otherwise, cancel and `await` the pending task to ensure proper
cleanup.
* Wrapped the `while loop.tick():` block in a `try/finally` to guarantee
`_cleanup_waiter()` runs on exit.
* Added missing `import contextlib`.

### Impact

* Prevents orphaned `stream.wait()` tasks.
* Removes noisy `"Task was destroyed but it is pending!"` warnings.
* Behavior of async streaming remains unchanged, only lifecycle
management improved.

### Test Plan

* Reproduced the issue by running async streaming with cancellation.
* Verified warnings no longer appear after the fix.
* Ran existing test suite (all passing).

### Notes

* Sync and Async implementations now follow the same principle: *only
one waiter at a time, always cleaned up on exit*.
* Backwards-compatible; no API changes.


### Repro & Verification

To confirm the issue and the fix I used the following minimal repro
snippet:

```python
# lg_repro.py
import asyncio
import os

# Enable asyncio debug logs to surface pending task warnings
os.environ.setdefault("PYTHONASYNCIODEBUG", "1")

from langgraph.graph import START, END, StateGraph

State = dict

# Slow async node: processes once, then sleeps to keep the waiter alive
async def slow_node(state: State) -> State:
    await asyncio.sleep(0.2)  # simulate work
    state["count"] = state.get("count", 0) + 1
    await asyncio.sleep(1.0)  # keep stream.wait() waiter active
    return state

# Build simple graph: START -> slow_node -> END
builder = StateGraph(State)
builder.add_node("slow", slow_node)
builder.add_edge(START, "slow")
builder.add_edge("slow", END)
graph = builder.compile()

async def run_and_cancel():
    # astream with messages mode triggers internal stream.wait() waiter
    async def consumer():
        async for _ in graph.astream({"msg": "hi"}, stream_mode="messages"):
            await asyncio.sleep(0.05)

    t = asyncio.create_task(consumer(), name="astream-consumer")

    # Allow the stream to start, then cancel the consumer
    await asyncio.sleep(0.1)
    t.cancel()
    try:
        await t
    except asyncio.CancelledError:
        pass

    # Let loop settle to show pending waiter task if not cleaned
    await asyncio.sleep(0.05)

def main():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.set_debug(True)
    try:
        loop.run_until_complete(run_and_cancel())
    finally:
        # If the internal waiter is not cleaned, closing the loop will warn
        loop.close()

if __name__ == "__main__":
    main()
````

**How to run**

```powershell
# Before (main branch)
git checkout main
pip install -e libs/langgraph
$env:PYTHONASYNCIODEBUG=1; python lg_repro.py

# After (patched branch)
git checkout async-waiter-cleanup
pip install -e libs/langgraph
$env:PYTHONASYNCIODEBUG=1; python lg_repro.py
```

**Observed results**

* **main branch (before fix):**
  Shows warnings like:

  ```
  Task was destroyed but it is pending!
  ... coro=<AsyncQueue.wait() ...>
  created at langgraph/pregel/main.py:2927
  ```
* **patched branch (after fix):**
No warnings. The single waiter is properly cleaned up on exit via
`_cleanup_waiter()` (release semaphore if available, then cancel/await).

---

This confirms that the patch removes the orphaned `stream.wait()` task
and prevents
`"Task was destroyed but it is pending!"` warnings during
cancellation/shutdown.

---------

Co-authored-by: Caspar Broekhuizen <caspar@langchain.dev>
2025-09-23 17:11:17 -07:00
Caspar BroekhuizenandGitHub affaa90d2a fix(langgraph): fix graph rendering for defer=True (#6130)
### Description

Some graphs with `defer=True` nodes rendered incorrectly. E.g.:
* edge C2 -> E1 is missing and edge C2 -> END should not appear in #5772
* edge E3 -> END is missing and edge E -> END should not appear in #5182
* extra edge #5369

Fix:
* Record the destinations declared by get_static_writes for each node.
Build step_sources as a union of the runtime writes and the static
writes (instead of just runtime writes).
* Label deferred nodes with 'deferred'

### https://github.com/langchain-ai/langgraph/issues/5772

'Before' is how they were rendered before this PR

| No defer    | Before (defer `E1`) | After (defer `E1`)
| -------- | ------- | ------- |
| <img height="400" alt="defer_after"
src="https://github.com/user-attachments/assets/0a9fc992-1b6a-4c6d-8752-de54c703c329"
/> | <img height="400" alt="defer_before"
src="https://github.com/user-attachments/assets/825b09fc-3fb8-461a-9928-20c8d9cfc533"
/> | <img height="400" alt="defer_after"
src="https://github.com/user-attachments/assets/ce5334f7-b469-47b0-8f1e-35bda2544a4e"
/> |

Before:
* For deferred joins (NamedBarrierValueAfterFinish), a writer from an
upstream node may not produce a runtime task.writes entry until the
barrier opens. draw_graph() builds edges from task.writes, so one side
of the join (here C2) never gets recorded as a source, and C2 is seen as
a sink, so there is an implicit edge: C2 -> END edge added.

After:
* C2's write to the join channel is recorded even if the barrier hasn’t
opened. When E1 finally schedules, we correctly find both sources B2 and
C2 for the same trigger and emit edges: B2 -> E1 and C2 -> E1.

With C2 -> E1 present, C2 is no longer a terminus, so the unexpected
edge: C2 -> END is not added.

### Other graphs

Graphs for the most part remain unchanged. See: 

### #5182 

| No defer    | Before (defer `d`) | After (defer `d`)
| -------- | ------- | ------- |
| <img height="400" alt="defer_after"
src="https://github.com/user-attachments/assets/3509d25c-f3ad-473c-b877-c155b8008cd5"
/> | <img height="400" alt="defer_before"
src="https://github.com/user-attachments/assets/7af38e77-eb70-414d-b8fe-667da943f9e0"
/> | <img height="400" alt="defer_after"
src="https://github.com/user-attachments/assets/bc87a19f-b4fb-42d3-a6ee-5b0982d9af71"
/> |

### https://github.com/langchain-ai/langgraph/issues/5369

| No defer | Before (defer `595577`, `52642`) | After (defer `595577`,
`52642`)
| -------- | ------- | ------- |
| <img height="400" alt="defer_after"
src="https://github.com/user-attachments/assets/7c0824ce-3921-4dce-bc16-278f64289d28"
/> | <img height="400" alt="defer_before"
src="https://github.com/user-attachments/assets/28661079-7502-4912-874b-c086c0204a87"
/> | <img height="400" alt="defer_after"
src="https://github.com/user-attachments/assets/2a04956a-ed79-40e5-98b8-f6ecb2597a2e"
/> |
2025-09-23 12:47:50 -07:00
shaktiman101GitHubgoogle-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>William FHCaspar Broekhuizen
9f969f5fe1 fix(checkpoint-sqlite): Handle TTL refresh correctly in AsyncSqliteStore.asearch (#5213)
The original implementation for `refresh_on_read=True` in `asearch` for
AsyncSqliteStore used a CTE with an UPDATE statement, which is not
well-supported by SQLite in that specific construction, leading to a
syntax error.

This commit changes the approach:
1. `_prepare_batch_search_queries` in `BaseSqliteStore` no longer
constructs a CTE-based UPDATE. Instead, it returns a flag indicating if
TTL refresh is needed for the searched items.
2. `_batch_search_ops` in both `AsyncSqliteStore` and `SqliteStore` now
check this flag. If true, they perform a separate UPDATE statement after
fetching the search results to refresh the TTL of those items.

Additionally, a new test case `test_async_asearch_refresh_ttl` was added
and existing test logic was refined to accurately verify this behavior.

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com>
Co-authored-by: Caspar Broekhuizen <caspar@langchain.dev>
2025-09-23 10:25:06 -07:00
Parker J. RuleandGitHub fb531b2473 feat(cli): add configuration for server customization ordering (#6179)
This adds a configuration option in `HttpConfig` that allows LangGraph
Platform users to apply custom authentication hooks before (other)
custom middleware. Currently, the order is fixed (custom middleware is
always evaluated before custom auth).

(Apologies for the noise in
[de187a9](https://github.com/langchain-ai/langgraph/pull/6179/commits/de187a989e807c5687c22db1fc065d24030fa6b7),
apparently from the forced application of new linter rules.)
2025-09-22 11:17:24 -04:00
fe4029b3b8 chore(deps): upgrade dependencies with uv lock --upgrade (#6176)
This PR updates the dependencies in all Python packages using `uv lock
--upgrade`.

This is an automated PR created by the UV Lock Upgrade workflow.

Co-authored-by: sydney-runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-09-22 10:21:40 -04:00
Nuno CamposandGitHub 7cd9a8e5dd sdk-py 0.2.9 2025-09-20 19:47:04 +01:00
Nuno CamposandGitHub 5ba02d5b46 feat: sdk-py: Reconnect to long-lived responses on wait/join/cancel endpoints (#6168)
- When connection is dropped while waiting, reconnect up to 5 times if a
Location header is present
2025-09-20 19:44:07 +01:00
Caspar BroekhuizenandGitHub 11834512db test(cli): add tests for util.py (#6172)
### Description

Added unit tests for util.py.

Authored by @oumizx. Had to copy #6113 into this separate PR because
langgraph/libs/cli was having issues with secrets.
2025-09-19 17:17:05 -07:00
eeb731c07e test: Add tests for before and limit parameters for list SqliteSaver (#5816)
**Description:** 

Add test for before and limit parameters for the list in SqliteSaver
which was marked as TODO.

---------

Co-authored-by: Caspar Broekhuizen <caspar@langchain.dev>
2025-09-19 16:53:30 -07:00
f0fced262a fix(langgraph): fix PostgresSaver crashing when loading older checkpoints (#6162)
### Description

https://github.com/langchain-ai/langgraph/issues/6137 and
https://github.com/langchain-ai/langgraph/issues/5677 reported issues
where older checkpoints read by AsyncPostgresSaver/PostgresSaver from
`langgraph-checkpoint-postgres==2.0.19` fail to read channel values,
throwing `NoneType object is not a mapping`. This was due to a bug in
how `channel_values` is assembled:
```python
"channel_values": {
    **value["checkpoint"].get("channel_values"),  # <--- if channel_values doesn't exist (old checkpoint), **None errors
    **self._load_blobs(value["channel_values"]),
},
```
This bug was observed for checkpoints generated by
`langgraph-checkpoint-postgres<=2.0.19`.

Fixed by providing a fallback to
`value["checkpoint"].get("channel_values")`:
```python
**value["checkpoint"],
"channel_values": {
    **(
        value["checkpoint"].get("channel_values") or {}
    ),  # 'or {}' needed for backwards compat with v3 checkpoints and below, as v4 introduced channel_values key
    **self._load_blobs(value["channel_values"]),
},
```

### Tests
Added test for AsyncPostgresSaver and test for PostgresSaver, using
monkeypatch to remove `channel_values` before CheckpointTuple is
assembled in `_load_checkpoint_tuple`.

### Solves
https://github.com/langchain-ai/langgraph/issues/6137 and
https://github.com/langchain-ai/langgraph/issues/5677

---------

Co-authored-by: Shahrukh Shaik <144558473+shahrukh-shaik@users.noreply.github.com>
2025-09-17 17:50:39 -07:00
8dc4465d05 fix(langgraph): reuse cached writes on nested resume to prevent task re-execution (#6161)
**Description**: fix #6050. 

Root cause: In nested graphs, the first tick after resume often included
a checkpoint_id, which set skip_done_tasks=False. This skipped matching
pending writes and re-executed already-completed helper @task on
subsequent resumes.

Change: Initialize skip_done_tasks=True when resuming inside a nested
graph. Use original config[CONF] for checkpoint_id presence, and
self.config[CONF] for resuming (current loop state). Added a concise
comment clarifying the different config sources.

**Issue**: #6050 

**Tests**: 
Add regression test `test_nested_graph_resume_reuses_cached_task_writes`

---------

Signed-off-by: jitokim <pigberger70@gmail.com>
Co-authored-by: Caspar Broekhuizen <casparbroekhuizen@gmail.com>
2025-09-17 12:35:07 -07:00
Nuno CamposandGitHub d0a3eaf601 sdk-py 0.2.8 2025-09-17 18:23:53 +01:00
Nuno CamposandGitHub 6f45f13952 fix: Handle SSE stream reconnection in Python SDK (#6159)
## Summary
- add a public accessor for the last received SSE event id
- retry async and sync SSE streams using the Location reconnect path and
Last-Event-ID while skipping empty events
- add regression tests that simulate interrupted SSE streams for both
async and sync clients

## Testing
- make format
- make lint
- make test

------
https://chatgpt.com/codex/tasks/task_e_68ca8bfa26cc832d98bcb359884962ec
2025-09-17 13:21:35 -04:00
Isaac FranciscoandGitHub 328129e5bd chore(sdk-py): allow UUIDs in config (#6151) 2025-09-17 09:57:47 -04:00
Caspar BroekhuizenandGitHub 2d05a17dfb fix(checkpoint): use tolerant float comparison to fix test failing on x86_64 architecture (#6157)
### Description

`test_embed_with_path` was failing on x86_64 architecture due to numeric
precision differences. `pytest.approx` was already used later on in this
test for float comparison, so this PR just updates a missed assertion.

Fixes https://github.com/langchain-ai/langgraph/issues/5845
2025-09-16 16:42:20 -07:00
Nuno Campos 5a36229e38 sdk-py 0.2.7 2025-09-16 16:29:27 +01:00
Nuno CamposandGitHub eeadeb282e fix: Ensure SSE streams flush trailing events (#6155)
## Summary
- ensure both async and sync HTTP clients flush the SSE decoder after
streaming
- add regression tests covering trailing SSE events without a
terminating blank line

## Testing
- make format
- make lint
- make test

------
https://chatgpt.com/codex/tasks/task_e_68c9727ca9f8832d9f207323c5e02a72
2025-09-16 16:25:47 +01:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
3a22aa0af3 chore(deps): bump actions/github-script from 7 to 8 (#6150)
Bumps [actions/github-script](https://github.com/actions/github-script)
from 7 to 8.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/github-script/releases">actions/github-script's
releases</a>.</em></p>
<blockquote>
<h2>v8.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update Node.js version support to 24.x by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/637">actions/github-script#637</a></li>
<li>README for updating actions/github-script from v7 to v8 by <a
href="https://github.com/sneha-krip"><code>@​sneha-krip</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/653">actions/github-script#653</a></li>
</ul>
<h2>⚠️ Minimum Compatible Runner Version</h2>
<p><strong>v2.327.1</strong><br />
<a
href="https://github.com/actions/runner/releases/tag/v2.327.1">Release
Notes</a></p>
<p>Make sure your runner is updated to this version or newer to use this
release.</p>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/github-script/pull/637">actions/github-script#637</a></li>
<li><a
href="https://github.com/sneha-krip"><code>@​sneha-krip</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/github-script/pull/653">actions/github-script#653</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/github-script/compare/v7.1.0...v8.0.0">https://github.com/actions/github-script/compare/v7.1.0...v8.0.0</a></p>
<h2>v7.1.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Upgrade husky to v9 by <a
href="https://github.com/benelan"><code>@​benelan</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/482">actions/github-script#482</a></li>
<li>Add workflow file for publishing releases to immutable action
package by <a
href="https://github.com/Jcambass"><code>@​Jcambass</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/485">actions/github-script#485</a></li>
<li>Upgrade IA Publish by <a
href="https://github.com/Jcambass"><code>@​Jcambass</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/486">actions/github-script#486</a></li>
<li>Fix workflow status badges by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/497">actions/github-script#497</a></li>
<li>Update usage of <code>actions/upload-artifact</code> by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/512">actions/github-script#512</a></li>
<li>Clear up package name confusion by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/514">actions/github-script#514</a></li>
<li>Update dependencies with <code>npm audit fix</code> by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/515">actions/github-script#515</a></li>
<li>Specify that the used script is JavaScript by <a
href="https://github.com/timotk"><code>@​timotk</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/478">actions/github-script#478</a></li>
<li>chore: Add Dependabot for NPM and Actions by <a
href="https://github.com/nschonni"><code>@​nschonni</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/472">actions/github-script#472</a></li>
<li>Define <code>permissions</code> in workflows and update actions by
<a href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in
<a
href="https://redirect.github.com/actions/github-script/pull/531">actions/github-script#531</a></li>
<li>chore: Add Dependabot for .github/actions/install-dependencies by <a
href="https://github.com/nschonni"><code>@​nschonni</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/532">actions/github-script#532</a></li>
<li>chore: Remove .vscode settings by <a
href="https://github.com/nschonni"><code>@​nschonni</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/533">actions/github-script#533</a></li>
<li>ci: Use github/setup-licensed by <a
href="https://github.com/nschonni"><code>@​nschonni</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/473">actions/github-script#473</a></li>
<li>make octokit instance available as octokit on top of github, to make
it easier to seamlessly copy examples from GitHub rest api or octokit
documentations by <a
href="https://github.com/iamstarkov"><code>@​iamstarkov</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/508">actions/github-script#508</a></li>
<li>Remove <code>octokit</code> README updates for v7 by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/557">actions/github-script#557</a></li>
<li>docs: add &quot;exec&quot; usage examples by <a
href="https://github.com/neilime"><code>@​neilime</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/546">actions/github-script#546</a></li>
<li>Bump ruby/setup-ruby from 1.213.0 to 1.222.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/github-script/pull/563">actions/github-script#563</a></li>
<li>Bump ruby/setup-ruby from 1.222.0 to 1.229.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/github-script/pull/575">actions/github-script#575</a></li>
<li>Clearly document passing inputs to the <code>script</code> by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/603">actions/github-script#603</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/github-script/pull/610">actions/github-script#610</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/benelan"><code>@​benelan</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/github-script/pull/482">actions/github-script#482</a></li>
<li><a href="https://github.com/Jcambass"><code>@​Jcambass</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/github-script/pull/485">actions/github-script#485</a></li>
<li><a href="https://github.com/timotk"><code>@​timotk</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/github-script/pull/478">actions/github-script#478</a></li>
<li><a
href="https://github.com/iamstarkov"><code>@​iamstarkov</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/github-script/pull/508">actions/github-script#508</a></li>
<li><a href="https://github.com/neilime"><code>@​neilime</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/github-script/pull/546">actions/github-script#546</a></li>
<li><a href="https://github.com/nebuk89"><code>@​nebuk89</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/github-script/pull/610">actions/github-script#610</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/github-script/compare/v7...v7.1.0">https://github.com/actions/github-script/compare/v7...v7.1.0</a></p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/github-script/commit/ed597411d8f924073f98dfc5c65a23a2325f34cd"><code>ed59741</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/github-script/issues/653">#653</a>
from actions/sneha-krip/readme-for-v8</li>
<li><a
href="https://github.com/actions/github-script/commit/2dc352e4baefd91bec0d06f6ae2f1045d1687ca3"><code>2dc352e</code></a>
Bold minimum Actions Runner version in README</li>
<li><a
href="https://github.com/actions/github-script/commit/01e118c8d0d22115597e46514b5794e7bc3d56f1"><code>01e118c</code></a>
Update README for Node 24 runtime requirements</li>
<li><a
href="https://github.com/actions/github-script/commit/8b222ac82eda86dcad7795c9d49b839f7bf5b18b"><code>8b222ac</code></a>
Apply suggestion from <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a></li>
<li><a
href="https://github.com/actions/github-script/commit/adc0eeac992408a7b276994ca87edde1c8ce4d25"><code>adc0eea</code></a>
README for updating actions/github-script from v7 to v8</li>
<li><a
href="https://github.com/actions/github-script/commit/20fe497b3fe0c7be8aae5c9df711ac716dc9c425"><code>20fe497</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/github-script/issues/637">#637</a>
from actions/node24</li>
<li><a
href="https://github.com/actions/github-script/commit/e7b7f222b11a03e8b695c4c7afba89a02ea20164"><code>e7b7f22</code></a>
update licenses</li>
<li><a
href="https://github.com/actions/github-script/commit/2c81ba05f308415d095291e6eeffe983d822345b"><code>2c81ba0</code></a>
Update Node.js version support to 24.x</li>
<li>See full diff in <a
href="https://github.com/actions/github-script/compare/v7...v8">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/github-script&package-manager=github_actions&previous-version=7&new-version=8)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-15 14:00:34 -04:00
Caspar BroekhuizenandGitHub 9467a0e2bb revert(langgraph): restore logic to surface interrupts for stream_mod… (#6141)
### Description

Revert change in #5201 that prevented the surfacing of interrupts when
`stream_mode="values"`. [Comment highlighting affected
lines](https://github.com/langchain-ai/langgraph/pull/5201#discussion_r2344884841)

Resolves #5409 

### Test

Add test to verify interrupts are properly surfaced when
`stream_mode="values"` (`test_interrupt_stream_mode_values`)
2025-09-14 19:11:19 -07:00
8b55dff7a5 chore(deps): upgrade dependencies with uv lock --upgrade (#6146)
This PR updates the dependencies in all Python packages using `uv lock
--upgrade`.

This is an automated PR created by the UV Lock Upgrade workflow.

To make tests pass:
* linting fixes
* whitespace fixes in snapshots

---------

Co-authored-by: sydney-runkle <54324534+sydney-runkle@users.noreply.github.com>
Co-authored-by: Sydney Runkle <sydneymarierunkle@gmail.com>
2025-09-14 19:36:43 -04:00
Huaiwu LiandGitHub a19b74154a docs: Add missing merge parameter documentation in push_ui_message (#6145)
**Description:**
This PR adds missing documentation for the `merge` parameter in the
`push_ui_message` function. The parameter was present in the function
signature but lacked documentation in the docstring, which could confuse
API users.

  Changes made:
  - Added clear documentation for the `merge` parameter
  - Explains the behavior difference between `merge=True`
  (merges props) and `merge=False` (replaces props)
  - Includes default value information

  **Issue:**
  N/A - Documentation improvement

  **Dependencies:**
  None
2025-09-14 23:34:34 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
0607dc4611 chore(deps): bump hono from 4.9.6 to 4.9.7 in /docs/_scripts/js_translation/codeblocks (#6143)
Bumps [hono](https://github.com/honojs/hono) from 4.9.6 to 4.9.7.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/honojs/hono/releases">hono's
releases</a>.</em></p>
<blockquote>
<h2>v4.9.7</h2>
<h2>Security</h2>
<ul>
<li>Fixed an issue in the <code>bodyLimit</code> middleware where the
body size limit could be bypassed when both <code>Content-Length</code>
and <code>Transfer-Encoding</code> headers were present. If you are
using this middleware, please update immediately. <a
href="https://github.com/honojs/hono/security/advisories/GHSA-92vj-g62v-jqhh">Security
Advisory</a></li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>fix(client): Fix <code>parseResponse</code> not parsing json in
react native by <a
href="https://github.com/lr0pb"><code>@​lr0pb</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/4399">honojs/hono#4399</a></li>
<li>chore: add <code>.tool-versions</code> file by <a
href="https://github.com/3w36zj6"><code>@​3w36zj6</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/4397">honojs/hono#4397</a></li>
<li>chore: update <code>bun install</code> commands to use
<code>--frozen-lockfile</code> by <a
href="https://github.com/3w36zj6"><code>@​3w36zj6</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/4398">honojs/hono#4398</a></li>
<li>test(jwk): Add tests of JWK token verification by <a
href="https://github.com/buckett"><code>@​buckett</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/4402">honojs/hono#4402</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/lr0pb"><code>@​lr0pb</code></a> made
their first contribution in <a
href="https://redirect.github.com/honojs/hono/pull/4399">honojs/hono#4399</a></li>
<li><a href="https://github.com/buckett"><code>@​buckett</code></a> made
their first contribution in <a
href="https://redirect.github.com/honojs/hono/pull/4402">honojs/hono#4402</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/honojs/hono/compare/v4.9.6...v4.9.7">https://github.com/honojs/hono/compare/v4.9.6...v4.9.7</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/honojs/hono/commit/5ece99500fbcdc1026ab7f458f65cbe9eab29a6b"><code>5ece995</code></a>
4.9.7</li>
<li><a
href="https://github.com/honojs/hono/commit/605c70560b52f13af10379f79b76717042fafe8d"><code>605c705</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/honojs/hono/commit/6792789ec06bd14c96ecdf38a368f7d7526e601a"><code>6792789</code></a>
test(jwk): Add tests of JWK token verification (<a
href="https://redirect.github.com/honojs/hono/issues/4402">#4402</a>)</li>
<li><a
href="https://github.com/honojs/hono/commit/2f489b3562cd0d29075062b2ea0648ab92b88727"><code>2f489b3</code></a>
chore: update <code>bun install</code> commands to use
<code>--frozen-lockfile</code> (<a
href="https://redirect.github.com/honojs/hono/issues/4398">#4398</a>)</li>
<li><a
href="https://github.com/honojs/hono/commit/9b0a8f51ed15910b86cd2a6dd8f15b16b45e1c06"><code>9b0a8f5</code></a>
chore: add <code>.tool-versions</code> file (<a
href="https://redirect.github.com/honojs/hono/issues/4397">#4397</a>)</li>
<li><a
href="https://github.com/honojs/hono/commit/5b277d811cc655667683ae60141f739fa40b65e1"><code>5b277d8</code></a>
fix(client): Fix <code>parseResponse</code> not parsing json in react
native (<a
href="https://redirect.github.com/honojs/hono/issues/4399">#4399</a>)</li>
<li>See full diff in <a
href="https://github.com/honojs/hono/compare/v4.9.6...v4.9.7">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=hono&package-manager=npm_and_yarn&previous-version=4.9.6&new-version=4.9.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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-09-14 19:11:30 -04:00
William FHandGitHub a3ee814539 chore(langgraph): Log when no values event is emitted from RemoteGraph (#6140) 2025-09-12 14:05:07 -07:00
William FHandGitHub b65140a892 chore(cli): Add config schema (#6142)
So you can IDE LSP support / autocompletion
2025-09-12 12:16:07 -07:00
Tadeo Donegana BraunschweigandGitHub 77a63608d1 docs: Update broken link in persistence_postgres.ipynb (#6135)
* Updated the relocation notice in `examples/persistence_postgres.ipynb`
to reference the correct new documentation at `add-memory.md` instead of
the previous notebook link.
2025-09-12 10:56:01 -04:00
Isaac FranciscoandGitHub c6179ca9d5 fix(cli): fix CLI integration test (#6129)
CLI integration tests were failing due to missing env vars, just needed
to copy to the places where the build commands were running from
2025-09-10 16:45:49 -07:00
f087567853 fix(cli): handle Docker SemVer build metadata in version parsing #5965 (#6024)
Description:
Corrects _parse_version to support Docker versions with SemVer build
metadata (e.g., 28.1.1+1), resolving #5965. Adds comprehensive unit
tests for version parsing, including normal, v-prefixed, prerelease,
build metadata, combined prerelease/build metadata, and edge cases with
missing components.

Issue:
Closes #5965

Dependencies:
None

---------

Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-09-10 14:31:07 -04:00
bdef6b3f5d fix(langgraph): get_graph generates unexpected conditional edge (#6122)
### Description

* Fix `get_graph()` generating an unexpected conditional edge to
`__end__` when the last step has a single (non-terminal) source and the
graph is cyclic.

### Issue
* There was a fallback path that was triggered in `draw_graph()` when,
for a Pregel instance; no termini exist and there is only a single step
source (the last one). In this case an edge was added: (last source) ->
`__end__`, even when another node already had a valid edge: (node) ->
`__end__`.

See this example:
<details>

<summary>code</summary>

```python
from langgraph.graph import END, START, StateGraph
from pydantic import BaseModel

class State(TypedDict):
    messages: list[str]

def chatbot_node(state: State) -> State:
    return {"messages": state["messages"] + ["chatbot"]}

def tools_node(state: State) -> State:
    return {"messages": state["messages"] + ["tools"]}

def human_node(state: State) -> State:
    return {"messages": state["messages"] + ["human"]}

def tools_condition(_: State) -> str:
    return "tools"

def end_condition(_: State) -> str:
    return "chatbot"

workflow = StateGraph(State)
workflow.add_node("chatbot", chatbot_node)
workflow.add_node("tools", tools_node)
workflow.add_node("human", human_node)

workflow.add_edge(START, "human")
workflow.add_edge("tools", "chatbot")
# graph_builder.add_edge("chatbot", "human") !!!

workflow.add_conditional_edges(
    "chatbot", tools_condition, {"tools": "tools", "human": "human"}
)
workflow.add_conditional_edges(
    "human", end_condition, {"chatbot": "chatbot", END: END}
)

app = workflow.compile()
mermaid = app.get_graph().draw_mermaid()
```

</details>

The code above, as-is, generates the graph on the left. There is an
unexpected conditional edge: chatbot -> `__end__`. If you uncomment the
commented line and introduce a static edge: chatbot -> human,
`get_graph()` returns the correct representation:

1 Without `graph_builder.add_edge("chatbot", "human")` | 2 With
`graph_builder.add_edge("chatbot", "human")`
:-------------------------:|:-------------------------:

![](https://github.com/user-attachments/assets/aa3149c2-ceee-4c0c-9c0c-e999caf042f0)
|
![](https://github.com/user-attachments/assets/ea53287f-1d68-47d6-8b36-9ec7ca1d52fa)

* In case 1), the graph is cyclic so termini is empty, and the last
`step_sources` set during the static walk contains only the chatbot
node, so an edge is added: chatbot -> `__end__`.
* In case 2), the graph is cyclic so termini is empty, and the last
`step_sources` set during the static walk contains only the human node,
so an edge is added: human -> `__end__`, but `add_edge()` dedups (the
edge already exists) so the graph appears correct.

### Solution
* Check that no valid edges: (node) -> `__end__` exist before triggering
the fallback path and creating an edge.

Before             |  After
:-------------------------:|:-------------------------:

![](https://github.com/user-attachments/assets/aa3149c2-ceee-4c0c-9c0c-e999caf042f0)
|
![](https://github.com/user-attachments/assets/9de4ab4f-6503-4894-bfda-37aba1d1be05)

After: The graph is cyclic so termini is empty, and the last
`step_sources` contains the chatbot node, but an edge already exists:
human -> `__end__`, so no more edges are added.

### Tests
* `test_get_graph_nonterminal_last_step_source()` which asserts no
unexpected edge to `__end__` is produced from the last nonterminal step
source.

### Issue

Closes #4394

---------

Co-authored-by: Sydney Runkle <sydneymarierunkle@gmail.com>
Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-09-10 11:28:33 -04:00
Sydney RunkleandGitHub 677d941bb6 fix(langgraph): type checking for async w/ functional API (#6126)
Fixes https://github.com/langchain-ai/langgraph/issues/4140
Fixes https://github.com/langchain-ai/langgraph/issues/3310
2025-09-10 11:26:02 -04:00
Sydney RunkleandGitHub a43acc33bd feat(langgraph): prevent arbitrary resumes w/ multiple pending interrupts (#6108)
The idea here is that we don't want to allow resuming a graph w/ an
arbitrary resume value if there are multiple interrupts in the queue,
because the order in which interrupts enter the queue is not
deterministic. We want to instead enforce that each resume value is
mapped to an interrupt id.

Instead, when multiple interrupts are present, a user should invoke w/ a
resume map, mapping interrupt id -> resume value.

The logic was more complex than expected because there are 2 copies of
an interrupt in `checkpoint_pending_writes` for the cases w/ the
functional API, because an interrupt in a task interrupts the task and
entrypoint.

This is technically breaking (users resuming multiple hanging interrupts
w/ multiple resume calls can no longer do this... but the behavior for
this case was non-deterministic in the first place so we can sell this
as a fix).
2025-09-10 08:31:11 -04:00
Sydney RunkleandGitHub 326fd55e4f fix(langgraph): key error on runtime for config w/o configurable (#6106)
Fixes https://github.com/langchain-ai/langgraph/issues/6072

Long term we probably want a more robust approach to configurable
management in terms of required / not required attributes.
2025-09-10 12:19:33 +00:00
Lauren Hirata SinghandGitHub 6037f0210f docs: Update banner for docs deprecation notice (#6120) 2025-09-09 20:33:11 -04:00
Sydney RunkleandGitHub d9328027f9 fix: use langgraph template for docs issue (#6121) 2025-09-09 18:20:15 -04:00
Sydney RunkleandGitHub 7170e04aa6 chore: update issue templates to redirect docs stuff (#6119) 2025-09-09 18:17:11 -04:00
20581e61c0 fix(checkpoint-postgres): export PoolConfig from package init (#5934)
### Description
Export PoolConfig from langgraph.store.postgres.__init__ so the
documented import from langgraph.store.postgres import
AsyncPostgresStore, PoolConfig works as shown in the AsyncPostgresStore
examples. This resolves a docs vs. code inconsistency without changing
behavior.

### Issue
N/A

### Dependencies:
None

---------

Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com>
Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-09-09 21:41:51 +00:00
4af07942ed chore(ci): Run CI int tests in parallel (#5976)
Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-09-09 19:01:12 +00:00
Caspar BroekhuizenandGitHub 682f39e0d3 fix(checkpoint): preserve non-ascii text in InMemoryStore embeddings (#6111)
### Description
* Set `ensure_ascii=False` for all `json.dumps` calls in
`get_text_at_path`. Preserves non-ASCII text instead of embedding
`\uXXXX` escapes.

**Before**
```python
store.put(("user_123", "memories"), "1", {"text": "这是中文"})
# embeds {"text": "\\u8fd9\\u662f\\u4e2d\\u6587"}
```

**After**
```python
store.put(("user_123", "memories"), "1", {"text": "这是中文"})
# embeds {"text": "这是中文"}
```

### Tests & Docs

* Add unit test `test_non_ascii` that writes three records (Chinese,
Japanese, Korean) to an `InMemoryStore`, searches with the same strings,
and asserts the correct top hit with a score >= 0.15 for each.

### Issue
Fixes #5946
2025-09-09 17:52:11 +00:00
Sakshi GuptaandGitHub 7bbe8d8628 docs: Update graph-api.md for "Extended example: specifying LLM at runtime" (#5938)
docs (graphapi) : Handle Missing Context in LLM Invocation - Invoking
the LLM without explicitly passing a context parameter resulted in the
following error:
`AttributeError: 'NoneType' object has no attribute 'model_provider'`
This occurred because the context was None, and the system attempted to
access model_provider. This PR ensures that when context is not
provided, an empty context is passed explicitly. This allows the system
to correctly fall back to the default value defined in the
ContextSchema.model_provider attribute.
2025-09-09 15:43:42 +00:00
4dfd1c368c Fix to graph-api docs Send API example (#5576)
Very small update to docs, I think there is an add_edge that shouldn't
be there and a bug.

Adding the Annotated, resolves this error I received running the
example.

Traceback (most recent call last):
File "/Users/toddchaney/repos/work/importal-apps/python-worker/main.py",
line 52, in <module>
for step in graph.stream({"topic": "animals"}, stream_mode = ["updates",
"values"]):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File
"/Users/toddchaney/repos/work/importal-apps/python-worker/.venv/lib/python3.12/site-packages/langgraph/pregel/__init__.py",
line 2544, in stream
    loop.after_tick()
File
"/Users/toddchaney/repos/work/importal-apps/python-worker/.venv/lib/python3.12/site-packages/langgraph/pregel/loop.py",
line 526, in after_tick
    self.updated_channels = apply_writes(
                            ^^^^^^^^^^^^^
File
"/Users/toddchaney/repos/work/importal-apps/python-worker/.venv/lib/python3.12/site-packages/langgraph/pregel/algo.py",
line 299, in apply_writes
    if channels[chan].update(vals) and next_version is not None:
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
File
"/Users/toddchaney/repos/work/importal-apps/python-worker/.venv/lib/python3.12/site-packages/langgraph/channels/last_value.py",
line 58, in update
    raise InvalidUpdateError(msg)
langgraph.errors.InvalidUpdateError: At key 'jokes': Can receive only
one value per step. Use an Annotated key to handle multiple values.
For troubleshooting, visit:
https://python.langchain.com/docs/troubleshooting/errors/INVALID_CONCURRENT_GRAPH_UPDATE

Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
2025-09-09 15:27:23 +00:00
b75daf093e docs(multi-agent page): fix a couple of broken links (#5813)
On this page:
https://langchain-ai.github.io/langgraph/concepts/multi_agent/
The last couple of links are broken

**First link:**

https://langchain-ai.github.io/langgraph/concepts/how-tos/subgraph.ipynb#different-state-schemas
should be updated to

https://langchain-ai.github.io/langgraph/how-tos/subgraph/#different-state-schemas

**Second link:**

https://langchain-ai.github.io/langgraph/concepts/how-tos/graph-api.ipynb#pass-private-state-between-nodes
should be updated to

https://langchain-ai.github.io/langgraph/how-tos/graph-api/#pass-private-state-between-nodes

---------

Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-09-09 15:14:25 +00:00
Mohammad MohtashimandGitHub faacbc1570 docs(prebuilt): remaining_steps explanation added in create_react_agent (#5847)
- **Description:** A better explanation of `remaining_steps` to clarify
what it does.
- **Issue:** #5548
2025-09-09 15:07:07 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Sydney Runkle
f5f536ba78 chore(deps): bump actions/download-artifact from 4 to 5 (#5868)
Bumps
[actions/download-artifact](https://github.com/actions/download-artifact)
from 4 to 5.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/download-artifact/releases">actions/download-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/download-artifact/pull/407">actions/download-artifact#407</a></li>
<li>BREAKING fix: inconsistent path behavior for single artifact
downloads by ID by <a
href="https://github.com/GrantBirki"><code>@​GrantBirki</code></a> in <a
href="https://redirect.github.com/actions/download-artifact/pull/416">actions/download-artifact#416</a></li>
</ul>
<h2>v5.0.0</h2>
<h3>🚨 Breaking Change</h3>
<p>This release fixes an inconsistency in path behavior for single
artifact downloads by ID. <strong>If you're downloading single artifacts
by ID, the output path may change.</strong></p>
<h4>What Changed</h4>
<p>Previously, <strong>single artifact downloads</strong> behaved
differently depending on how you specified the artifact:</p>
<ul>
<li><strong>By name</strong>: <code>name: my-artifact</code> → extracted
to <code>path/</code> (direct)</li>
<li><strong>By ID</strong>: <code>artifact-ids: 12345</code> → extracted
to <code>path/my-artifact/</code> (nested)</li>
</ul>
<p>Now both methods are consistent:</p>
<ul>
<li><strong>By name</strong>: <code>name: my-artifact</code> → extracted
to <code>path/</code> (unchanged)</li>
<li><strong>By ID</strong>: <code>artifact-ids: 12345</code> → extracted
to <code>path/</code> (fixed - now direct)</li>
</ul>
<h4>Migration Guide</h4>
<h5> No Action Needed If:</h5>
<ul>
<li>You download artifacts by <strong>name</strong></li>
<li>You download <strong>multiple</strong> artifacts by ID</li>
<li>You already use <code>merge-multiple: true</code> as a
workaround</li>
</ul>
<h5>⚠️ Action Required If:</h5>
<p>You download <strong>single artifacts by ID</strong> and your
workflows expect the nested directory structure.</p>
<p><strong>Before v5 (nested structure):</strong></p>
<pre lang="yaml"><code>- uses: actions/download-artifact@v4
  with:
    artifact-ids: 12345
    path: dist
# Files were in: dist/my-artifact/
</code></pre>
<blockquote>
<p>Where <code>my-artifact</code> is the name of the artifact you
previously uploaded</p>
</blockquote>
<p><strong>To maintain old behavior (if needed):</strong></p>
<pre lang="yaml"><code>&lt;/tr&gt;&lt;/table&gt; 
</code></pre>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/download-artifact/commit/634f93cb2916e3fdff6788551b99b062d0335ce0"><code>634f93c</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/416">#416</a>
from actions/single-artifact-id-download-path</li>
<li><a
href="https://github.com/actions/download-artifact/commit/b19ff4302770b82aa4694b63703b547756dacce6"><code>b19ff43</code></a>
refactor: resolve download path correctly in artifact download tests
(mainly ...</li>
<li><a
href="https://github.com/actions/download-artifact/commit/e262cbee4ab8c473c61c59a81ad8e9dc760e90db"><code>e262cbe</code></a>
bundle dist</li>
<li><a
href="https://github.com/actions/download-artifact/commit/bff23f9308ceb2f06d673043ea6311519be6a87b"><code>bff23f9</code></a>
update docs</li>
<li><a
href="https://github.com/actions/download-artifact/commit/fff8c148a8fdd56aa81fcb019f0b5f6c65700c4d"><code>fff8c14</code></a>
fix download path logic when downloading a single artifact by id</li>
<li><a
href="https://github.com/actions/download-artifact/commit/448e3f862ab3ef47aa50ff917776823c9946035b"><code>448e3f8</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/407">#407</a>
from actions/nebuk89-patch-1</li>
<li><a
href="https://github.com/actions/download-artifact/commit/47225c44b359a5155efdbbbc352041b3e249fb1b"><code>47225c4</code></a>
Update README.md</li>
<li>See full diff in <a
href="https://github.com/actions/download-artifact/compare/v4...v5">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/download-artifact&package-manager=github_actions&previous-version=4&new-version=5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-09-09 10:48:03 -04:00
Kenta MurataandGitHub 7284326160 fix(docs): Embed appropriate image files in graph-api.md (#6082)
This fixes some images that refer to incorrect files.
2025-09-09 14:42:26 +00:00
Shelton CuiandGitHub 62f7548532 docs(docs): fix incorrect return type in should_continue example (#6068)
Description:
The documentation for the should_continue function contained an
incorrect return type annotation.
It was shown as Literal["environment", END], but the actual logic
returns "Action" or END.

This PR updates the example to use Literal["Action", END] so that the
documentation matches the intended behavior of the function.

Issue:
N/A

Dependencies:
None
2025-09-09 14:33:27 +00:00
Sydney RunkleandGitHub e6a9e1d1c1 chore: update examples with context API (#5865) 2025-09-09 10:31:40 -04:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Sydney Runkle
94fa329100 chore(deps): bump actions/checkout from 4 to 5 (#5930)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to
5.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
<li>Prepare v5.0.0 release by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2238">actions/checkout#2238</a></li>
</ul>
<h2>⚠️ Minimum Compatible Runner Version</h2>
<p><strong>v2.327.1</strong><br />
<a
href="https://github.com/actions/runner/releases/tag/v2.327.1">Release
Notes</a></p>
<p>Make sure your runner is updated to this version or newer to use this
release.</p>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v4...v5.0.0">https://github.com/actions/checkout/compare/v4...v5.0.0</a></p>
<h2>v4.3.0</h2>
<h2>What's Changed</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
<li>Prepare release v4.3.0 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2237">actions/checkout#2237</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/motss"><code>@​motss</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li><a href="https://github.com/mouismail"><code>@​mouismail</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li><a href="https://github.com/benwells"><code>@​benwells</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li><a href="https://github.com/nebuk89"><code>@​nebuk89</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li><a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v4...v4.3.0">https://github.com/actions/checkout/compare/v4...v4.3.0</a></p>
<h2>v4.2.2</h2>
<h2>What's Changed</h2>
<ul>
<li><code>url-helper.ts</code> now leverages well-known environment
variables by <a href="https://github.com/jww3"><code>@​jww3</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li>
<li>Expand unit test coverage for <code>isGhes</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v4.2.1...v4.2.2">https://github.com/actions/checkout/compare/v4.2.1...v4.2.2</a></p>
<h2>v4.2.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Check out other refs/* by commit if provided, fall back to ref by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/Jcambass"><code>@​Jcambass</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/1919">actions/checkout#1919</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v4.2.0...v4.2.1">https://github.com/actions/checkout/compare/v4.2.0...v4.2.1</a></p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>V5.0.0</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
</ul>
<h2>V4.3.0</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<h2>v4.2.2</h2>
<ul>
<li><code>url-helper.ts</code> now leverages well-known environment
variables by <a href="https://github.com/jww3"><code>@​jww3</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li>
<li>Expand unit test coverage for <code>isGhes</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li>
</ul>
<h2>v4.2.1</h2>
<ul>
<li>Check out other refs/* by commit if provided, fall back to ref by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li>
</ul>
<h2>v4.2.0</h2>
<ul>
<li>Add Ref and Commit outputs by <a
href="https://github.com/lucacome"><code>@​lucacome</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1180">actions/checkout#1180</a></li>
<li>Dependency updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>- <a
href="https://redirect.github.com/actions/checkout/pull/1777">actions/checkout#1777</a>,
<a
href="https://redirect.github.com/actions/checkout/pull/1872">actions/checkout#1872</a></li>
</ul>
<h2>v4.1.7</h2>
<ul>
<li>Bump the minor-npm-dependencies group across 1 directory with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1739">actions/checkout#1739</a></li>
<li>Bump actions/checkout from 3 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1697">actions/checkout#1697</a></li>
<li>Check out other refs/* by commit by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1774">actions/checkout#1774</a></li>
<li>Pin actions/checkout's own workflows to a known, good, stable
version. by <a href="https://github.com/jww3"><code>@​jww3</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1776">actions/checkout#1776</a></li>
</ul>
<h2>v4.1.6</h2>
<ul>
<li>Check platform to set archive extension appropriately by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1732">actions/checkout#1732</a></li>
</ul>
<h2>v4.1.5</h2>
<ul>
<li>Update NPM dependencies by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1703">actions/checkout#1703</a></li>
<li>Bump github/codeql-action from 2 to 3 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1694">actions/checkout#1694</a></li>
<li>Bump actions/setup-node from 1 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1696">actions/checkout#1696</a></li>
<li>Bump actions/upload-artifact from 2 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1695">actions/checkout#1695</a></li>
<li>README: Suggest <code>user.email</code> to be
<code>41898282+github-actions[bot]@users.noreply.github.com</code> by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1707">actions/checkout#1707</a></li>
</ul>
<h2>v4.1.4</h2>
<ul>
<li>Disable <code>extensions.worktreeConfig</code> when disabling
<code>sparse-checkout</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1692">actions/checkout#1692</a></li>
<li>Add dependabot config by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1688">actions/checkout#1688</a></li>
<li>Bump the minor-actions-dependencies group with 2 updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1693">actions/checkout#1693</a></li>
<li>Bump word-wrap from 1.2.3 to 1.2.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1643">actions/checkout#1643</a></li>
</ul>
<h2>v4.1.3</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/checkout/commit/08c6903cd8c0fde910a37f88322edcfb5dd907a8"><code>08c6903</code></a>
Prepare v5.0.0 release (<a
href="https://redirect.github.com/actions/checkout/issues/2238">#2238</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/9f265659d3bb64ab1440b03b12f4d47a24320917"><code>9f26565</code></a>
Update actions checkout to use node 24 (<a
href="https://redirect.github.com/actions/checkout/issues/2226">#2226</a>)</li>
<li>See full diff in <a
href="https://github.com/actions/checkout/compare/v4...v5">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4&new-version=5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-09-09 14:28:41 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Sydney Runkle
264caa0684 chore(deps): bump amannn/action-semantic-pull-request from 5 to 6 (#5929)
Bumps
[amannn/action-semantic-pull-request](https://github.com/amannn/action-semantic-pull-request)
from 5 to 6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/amannn/action-semantic-pull-request/releases">amannn/action-semantic-pull-request's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.0</h2>
<h2><a
href="https://github.com/amannn/action-semantic-pull-request/compare/v5.5.3...v6.0.0">6.0.0</a>
(2025-08-13)</h2>
<h3>⚠ BREAKING CHANGES</h3>
<ul>
<li>Upgrade action to use Node.js 24 and ESM (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/287">#287</a>)</li>
</ul>
<h3>Features</h3>
<ul>
<li>Upgrade action to use Node.js 24 and ESM (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/287">#287</a>)
(<a
href="https://github.com/amannn/action-semantic-pull-request/commit/bc0c9a79abfe07c0f08c498dd4a040bd22fe9b79">bc0c9a7</a>)</li>
</ul>
<h2>v5.5.3</h2>
<h2><a
href="https://github.com/amannn/action-semantic-pull-request/compare/v5.5.2...v5.5.3">5.5.3</a>
(2024-06-28)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>Bump <code>braces</code> dependency (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/269">#269</a>.
by <a href="https://github.com/EelcoLos"><code>@​EelcoLos</code></a>)
(<a
href="https://github.com/amannn/action-semantic-pull-request/commit/2d952a1bf90a6a7ab8f0293dc86f5fdf9acb1915">2d952a1</a>)</li>
</ul>
<h2>v5.5.2</h2>
<h2><a
href="https://github.com/amannn/action-semantic-pull-request/compare/v5.5.1...v5.5.2">5.5.2</a>
(2024-04-24)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>Bump tar from 6.1.11 to 6.2.1 (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/262">#262</a>
by <a href="https://github.com/EelcoLos"><code>@​EelcoLos</code></a>)
(<a
href="https://github.com/amannn/action-semantic-pull-request/commit/9a90d5a5ac979326e3bb9272750cdd4f192ce24a">9a90d5a</a>)</li>
</ul>
<h2>v5.5.1</h2>
<h2><a
href="https://github.com/amannn/action-semantic-pull-request/compare/v5.5.0...v5.5.1">5.5.1</a>
(2024-04-24)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>Bump ip from 2.0.0 to 2.0.1 (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/263">#263</a>
by <a href="https://github.com/EelcoLos"><code>@​EelcoLos</code></a>)
(<a
href="https://github.com/amannn/action-semantic-pull-request/commit/5e7e9acca3ddc6a9d7b640fe1f905c4fff131f4a">5e7e9ac</a>)</li>
</ul>
<h2>v5.5.0</h2>
<h2><a
href="https://github.com/amannn/action-semantic-pull-request/compare/v5.4.0...v5.5.0">5.5.0</a>
(2024-04-23)</h2>
<h3>Features</h3>
<ul>
<li>Add outputs for <code>type</code>, <code>scope</code> and
<code>subject</code> (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/261">#261</a>
by <a href="https://github.com/bcaurel"><code>@​bcaurel</code></a>) (<a
href="https://github.com/amannn/action-semantic-pull-request/commit/b05f5f6423ef5cdfc7fdff00c4c10dd9a4f54aff">b05f5f6</a>)</li>
</ul>
<h2>v5.4.0</h2>
<h2><a
href="https://github.com/amannn/action-semantic-pull-request/compare/v5.3.0...v5.4.0">5.4.0</a>
(2023-11-03)</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/amannn/action-semantic-pull-request/blob/main/CHANGELOG.md">amannn/action-semantic-pull-request's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/amannn/action-semantic-pull-request/compare/v5.2.0...v5.3.0">5.3.0</a>
(2023-09-25)</h2>
<h3>Features</h3>
<ul>
<li>Use Node.js 20 in action (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/240">#240</a>)
(<a
href="https://github.com/amannn/action-semantic-pull-request/commit/4c0d5a21fc86635c67cc57ffe89d842c34ade284">4c0d5a2</a>)</li>
</ul>
<h2><a
href="https://github.com/amannn/action-semantic-pull-request/compare/v5.1.0...v5.2.0">5.2.0</a>
(2023-03-16)</h2>
<h3>Features</h3>
<ul>
<li>Update dependencies by <a
href="https://github.com/EelcoLos"><code>@​EelcoLos</code></a> (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/229">#229</a>)
(<a
href="https://github.com/amannn/action-semantic-pull-request/commit/e797448a07516738bcfdd6f26ad1d1f84c58d0cc">e797448</a>)</li>
</ul>
<h2><a
href="https://github.com/amannn/action-semantic-pull-request/compare/v5.0.2...v5.1.0">5.1.0</a>
(2023-02-10)</h2>
<h3>Features</h3>
<ul>
<li>Add regex support to <code>scope</code> and
<code>disallowScopes</code> configuration (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/226">#226</a>)
(<a
href="https://github.com/amannn/action-semantic-pull-request/commit/403a6f89242a0d0d3acde94e6141b2e0f4da8838">403a6f8</a>)</li>
</ul>
<h3><a
href="https://github.com/amannn/action-semantic-pull-request/compare/v5.0.1...v5.0.2">5.0.2</a>
(2022-10-17)</h3>
<h3>Bug Fixes</h3>
<ul>
<li>Upgrade <code>@actions/core</code> to avoid deprecation warnings (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/208">#208</a>)
(<a
href="https://github.com/amannn/action-semantic-pull-request/commit/91f4126c9e8625b9cadd64b02a03018fa22fc498">91f4126</a>)</li>
</ul>
<h3><a
href="https://github.com/amannn/action-semantic-pull-request/compare/v5.0.0...v5.0.1">5.0.1</a>
(2022-10-14)</h3>
<h3>Bug Fixes</h3>
<ul>
<li>Upgrade GitHub Action to use Node v16 (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/207">#207</a>)
(<a
href="https://github.com/amannn/action-semantic-pull-request/commit/6282ee339b067cb8eab05026f91153f873ad37fb">6282ee3</a>)</li>
</ul>
<h2><a
href="https://github.com/amannn/action-semantic-pull-request/compare/v4.6.0...v5.0.0">5.0.0</a>
(2022-10-11)</h2>
<h3>⚠ BREAKING CHANGES</h3>
<ul>
<li>Enum options need to be newline delimited (to allow whitespace
within them) (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/205">#205</a>)</li>
</ul>
<h3>Features</h3>
<ul>
<li>Enum options need to be newline delimited (to allow whitespace
within them) (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/205">#205</a>)
(<a
href="https://github.com/amannn/action-semantic-pull-request/commit/c906fe1e5a4bcc61624931ca94da9672107bd448">c906fe1</a>)</li>
</ul>
<h2><a
href="https://github.com/amannn/action-semantic-pull-request/compare/v4.5.0...v4.6.0">4.6.0</a>
(2022-09-26)</h2>
<h3>Features</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/amannn/action-semantic-pull-request/commit/fdd4d3ddf614fbcd8c29e4b106d3bbe0cb2c605d"><code>fdd4d3d</code></a>
chore: Release 6.0.1 [skip ci]</li>
<li><a
href="https://github.com/amannn/action-semantic-pull-request/commit/58e4ab40f59be79f2c432bf003e34a31174e977a"><code>58e4ab4</code></a>
fix: Actually execute action (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/289">#289</a>)</li>
<li><a
href="https://github.com/amannn/action-semantic-pull-request/commit/04a8d177d951f6d3dff9f6fbfa336354c60a1112"><code>04a8d17</code></a>
chore: Release 6.0.0 [skip ci]</li>
<li><a
href="https://github.com/amannn/action-semantic-pull-request/commit/bc0c9a79abfe07c0f08c498dd4a040bd22fe9b79"><code>bc0c9a7</code></a>
feat!: Upgrade action to use Node.js 24 and ESM (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/287">#287</a>)</li>
<li><a
href="https://github.com/amannn/action-semantic-pull-request/commit/631ffdc0283366e1d671846987cd2532bebcaba7"><code>631ffdc</code></a>
build(deps): bump the github-action-workflows group with 2 updates (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/286">#286</a>)</li>
<li><a
href="https://github.com/amannn/action-semantic-pull-request/commit/c1807ceb58850d1d23bc4bb1de293f0f07ddc198"><code>c1807ce</code></a>
build: configure Dependabot (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/231">#231</a>)</li>
<li><a
href="https://github.com/amannn/action-semantic-pull-request/commit/335288255954904a41ddda8947c8f2c844b8bfeb"><code>3352882</code></a>
docs: Remove <code>synchronize</code> trigger (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/281">#281</a>)</li>
<li><a
href="https://github.com/amannn/action-semantic-pull-request/commit/04501d43b574e4c1d23c629ffe4dcec27acfdeff"><code>04501d4</code></a>
docs: More restrictive permissions (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/280">#280</a>)</li>
<li><a
href="https://github.com/amannn/action-semantic-pull-request/commit/40166f00814508ec3201fc8595b393d451c8cd80"><code>40166f0</code></a>
chore: Update actions in release workflow (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/276">#276</a>)</li>
<li><a
href="https://github.com/amannn/action-semantic-pull-request/commit/80c0371c57c5142ed6c844270bba1864bac8a4c6"><code>80c0371</code></a>
docs: Mention <code>reopened</code> trigger in README (<a
href="https://redirect.github.com/amannn/action-semantic-pull-request/issues/272">#272</a>
by <a
href="https://github.com/garysassano"><code>@​garysassano</code></a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/amannn/action-semantic-pull-request/compare/v5...v6">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=amannn/action-semantic-pull-request&package-manager=github_actions&previous-version=5&new-version=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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-09-09 10:28:09 -04:00
Sydney RunkleandGitHub cd33de2ad1 chore: minor CI/link fixes (#6116) 2025-09-09 14:22:19 +00:00
692f177a10 docs(langgraph): unindent text (#5906)
**Description:** unintend wrongly indented bulleted list and paragraph.

Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
2025-09-09 14:19:24 +00:00
Sakshi GuptaandGitHub 14d4be6c4a docs: Import RetryPolicy from types not pregel (#5941)
docs (graphapi.md) : With the new langgraph version, the RetryPolicy
needs to be imported from `langgraph.types` to avoid `ImportError:
cannot import name 'RetryPolicy' from 'langgraph.pregel'`
2025-09-09 14:18:48 +00:00
Kathryn MayandGitHub 2e133d6189 docs: Add redirect to standalone server page (#5855)
add redirect for deployment name change
2025-09-09 10:17:14 -04:00
Xin ZhangandGitHub 89de950307 docs (langgraph): Fix bug in the code example (#6114)
- **Description:** Fix the wrong variable name in the example of
`memory.md`.
  - **Dependencies:** NA.
2025-09-09 12:17:07 +00:00
xindooandGitHub 788b62c0fb docs(langgraph):Correct variable name in context.md (#6022)
Ensures the variable name used in the documentation accurately reflects
the codebase.
2025-09-08 20:54:42 +00:00
zzxxj216andGitHub 1539a55d2c docs(langgraph): correct typo "runtie" to "runtime" in StateGraph (#6060)
**Description:** Fix a typo where "runtie" was incorrectly used instead
of "runtime" in line 158 of the StateGraph class in state.py. This
resolves the example error caused by the misspelled variable name.

**Dependencies:** None
2025-09-08 20:54:35 +00:00
Mohammad YehyaandGitHub f3055178f3 docs: Fix Example Code Snippet in HITL (#5999)
Description: Fixing the example code snippet at this
[url](https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/add-human-in-the-loop/#resume-multiple-interrupts-with-one-invocation).

Fixes: 
- i.interrupt_id -> i.id, since interrupt_id is deprecrated
- f"human input for prompt {i.value}" -> f"edited text for
{i.value['text_to_revise']}", to match the output statement
- parent.get_state -> graph.get_state, no variable named parent
- get_state(thread_config) -> get_state(config), no variable named
thread_config
2025-09-08 20:53:22 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Sydney Runkle
c0067cd304 chore: bump actions/upload-pages-artifact from 3 to 4 (#6004)
Bumps
[actions/upload-pages-artifact](https://github.com/actions/upload-pages-artifact)
from 3 to 4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/upload-pages-artifact/releases">actions/upload-pages-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v4.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Potentially breaking change: hidden files (specifically dotfiles)
will not be included in the artifact by <a
href="https://github.com/tsusdere"><code>@​tsusdere</code></a> in <a
href="https://redirect.github.com/actions/upload-pages-artifact/pull/102">actions/upload-pages-artifact#102</a>
If you need to include dotfiles in your artifact: instead of using this
action, create your own artifact according to these requirements <a
href="https://github.com/actions/upload-pages-artifact?tab=readme-ov-file#artifact-validation">https://github.com/actions/upload-pages-artifact?tab=readme-ov-file#artifact-validation</a></li>
<li>Pin <code>actions/upload-artifact</code> to SHA by <a
href="https://github.com/heavymachinery"><code>@​heavymachinery</code></a>
in <a
href="https://redirect.github.com/actions/upload-pages-artifact/pull/127">actions/upload-pages-artifact#127</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-pages-artifact/compare/v3.0.1...v4.0.0">https://github.com/actions/upload-pages-artifact/compare/v3.0.1...v4.0.0</a></p>
<h2>v3.0.1</h2>
<h1>Changelog</h1>
<ul>
<li>Group tar's output to prevent it from messing up action logs <a
href="https://github.com/SilverRainZ"><code>@​SilverRainZ</code></a> (<a
href="https://redirect.github.com/actions/upload-pages-artifact/issues/94">#94</a>)</li>
<li>Update README.md <a
href="https://github.com/uiolee"><code>@​uiolee</code></a> (<a
href="https://redirect.github.com/actions/upload-pages-artifact/issues/88">#88</a>)</li>
<li>Bump the non-breaking-changes group with 1 update <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> (<a
href="https://redirect.github.com/actions/upload-pages-artifact/issues/92">#92</a>)</li>
<li>Update Dependabot config to group non-breaking changes <a
href="https://github.com/JamesMGreene"><code>@​JamesMGreene</code></a>
(<a
href="https://redirect.github.com/actions/upload-pages-artifact/issues/91">#91</a>)</li>
<li>Bump actions/checkout from 3 to 4 <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> (<a
href="https://redirect.github.com/actions/upload-pages-artifact/issues/76">#76</a>)</li>
</ul>
<p>See details of <a
href="https://github.com/actions/upload-pages-artifact/compare/v3.0.0...v3.0.1">all
code changes</a> since previous release.</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/upload-pages-artifact/commit/7b1f4a764d45c48632c6b24a0339c27f5614fb0b"><code>7b1f4a7</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-pages-artifact/issues/127">#127</a>
from heavymachinery/pin-sha</li>
<li><a
href="https://github.com/actions/upload-pages-artifact/commit/4cc19c7d3f3e6c87c68366501382a03c8b1ba6db"><code>4cc19c7</code></a>
Pin <code>actions/upload-artifact</code> to SHA</li>
<li><a
href="https://github.com/actions/upload-pages-artifact/commit/2d163be3ddce01512f3eea7ac5b7023b5d643ce1"><code>2d163be</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-pages-artifact/issues/107">#107</a>
from KittyChiu/main</li>
<li><a
href="https://github.com/actions/upload-pages-artifact/commit/c70484322b1c476728dcd37fac23c4dea2a0c51a"><code>c704843</code></a>
fix: linted README</li>
<li><a
href="https://github.com/actions/upload-pages-artifact/commit/9605915f1d2fc79418cdce4d5fbe80511c457655"><code>9605915</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-pages-artifact/issues/106">#106</a>
from KittyChiu/kittychiu/update-readme-1</li>
<li><a
href="https://github.com/actions/upload-pages-artifact/commit/e59cdfe6d6b061aab8f0619e759cded914f3ab03"><code>e59cdfe</code></a>
Update README.md</li>
<li><a
href="https://github.com/actions/upload-pages-artifact/commit/a2d67043267d885050434d297d3dd3a3a14fd899"><code>a2d6704</code></a>
doc: updated usage section in readme</li>
<li><a
href="https://github.com/actions/upload-pages-artifact/commit/984864e7b70fb5cb764344dc9c4b5c087662ef50"><code>984864e</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-pages-artifact/issues/105">#105</a>
from actions/Jcambass-patch-1</li>
<li><a
href="https://github.com/actions/upload-pages-artifact/commit/45dc78884ca148c05eddcd8ac0a804d3365e9014"><code>45dc788</code></a>
Add workflow file for publishing releases to immutable action
package</li>
<li><a
href="https://github.com/actions/upload-pages-artifact/commit/efaad07812d4b9ad2e8667cd46426fdfb7c22e22"><code>efaad07</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-pages-artifact/issues/102">#102</a>
from actions/hidden-files</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/upload-pages-artifact/compare/v3...v4">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/upload-pages-artifact&package-manager=github_actions&previous-version=3&new-version=4)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-09-08 20:52:35 +00:00
Kenta MurataandGitHub b90d7c4e58 fix(docs): Fix indentation of info block in graph-api.md (#6081)
The "Why split application steps into a sequence with LangGraph?" info
block in `graph-api.md` is broken.

Before:
<img width="889" height="529" alt="image"
src="https://github.com/user-attachments/assets/7c60e4f0-7de2-4ffa-8493-ad958e4af211"
/>


After:
<img width="895" height="494" alt="image"
src="https://github.com/user-attachments/assets/3aefe0ca-1cb8-4d03-b1ed-7c3475204c88"
/>
2025-09-08 20:51:16 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2c14b1d658 chore bump hono from 4.8.9 to 4.9.6 in /docs/_scripts/js_translation/codeblocks (#6078)
Bumps [hono](https://github.com/honojs/hono) from 4.8.9 to 4.9.6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/honojs/hono/releases">hono's
releases</a>.</em></p>
<blockquote>
<h2>v4.9.6</h2>
<h2>Security</h2>
<p>Fixed a bug in URL path parsing (<code>getPath</code>) that could
cause path confusion under malformed requests.</p>
<p>If you rely on reverse proxies (e.g. Nginx) for ACLs or restrict
access to endpoints like <code>/admin</code>, please update
immediately.</p>
<p>See advisory for details: GHSA-9hp6-4448-45g2</p>
<h2>What's Changed</h2>
<ul>
<li>chore: update packages in the router bench by <a
href="https://github.com/yusukebe"><code>@​yusukebe</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/4386">honojs/hono#4386</a></li>
<li>chore(benchmarks): remove comment-out from router bench by <a
href="https://github.com/yusukebe"><code>@​yusukebe</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/4387">honojs/hono#4387</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/honojs/hono/compare/v4.9.5...v4.9.6">https://github.com/honojs/hono/compare/v4.9.5...v4.9.6</a></p>
<h2>v4.9.5</h2>
<h2>What's Changed</h2>
<ul>
<li>chore: replace supertest with undici by <a
href="https://github.com/BarryThePenguin"><code>@​BarryThePenguin</code></a>
in <a
href="https://redirect.github.com/honojs/hono/pull/4365">honojs/hono#4365</a></li>
<li>fix(aws-lambda): preserve percent-encoded values in query strings by
<a href="https://github.com/yusukebe"><code>@​yusukebe</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/4372">honojs/hono#4372</a></li>
<li>feat(cors): Allow async functions for <code>origin</code> and
<code>allowMethods</code> by <a
href="https://github.com/jobrk"><code>@​jobrk</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/4373">honojs/hono#4373</a></li>
<li>feat(cors): Correct origin function return type asynchronously
returning null or undefined for origin by <a
href="https://github.com/jobrk"><code>@​jobrk</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/4375">honojs/hono#4375</a></li>
<li>fix(service-worker): correct args for <code>app.fetch</code> in
<code>handle</code> by <a
href="https://github.com/yusukebe"><code>@​yusukebe</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/4374">honojs/hono#4374</a></li>
<li>fix(language-detector): Detect language from path after getPath
changed by <a
href="https://github.com/iflamed"><code>@​iflamed</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/4369">honojs/hono#4369</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/jobrk"><code>@​jobrk</code></a> made
their first contribution in <a
href="https://redirect.github.com/honojs/hono/pull/4373">honojs/hono#4373</a></li>
<li><a href="https://github.com/iflamed"><code>@​iflamed</code></a> made
their first contribution in <a
href="https://redirect.github.com/honojs/hono/pull/4369">honojs/hono#4369</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/honojs/hono/compare/v4.9.4...v4.9.5">https://github.com/honojs/hono/compare/v4.9.4...v4.9.5</a></p>
<h2>v4.9.4</h2>
<h2>What's Changed</h2>
<ul>
<li>chore: add a type cast to run <code>deno publish</code> by <a
href="https://github.com/yusukebe"><code>@​yusukebe</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/4364">honojs/hono#4364</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/honojs/hono/compare/v4.9.3...v4.9.4">https://github.com/honojs/hono/compare/v4.9.3...v4.9.4</a></p>
<h2>v4.9.3</h2>
<h2>What's Changed</h2>
<ul>
<li>feat(csrf): Add modern CSRF protection with Fetch Metadata support
by <a href="https://github.com/meck93"><code>@​meck93</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/4353">honojs/hono#4353</a></li>
<li>tests: use vitest projects by <a
href="https://github.com/BarryThePenguin"><code>@​BarryThePenguin</code></a>
in <a
href="https://redirect.github.com/honojs/hono/pull/4359">honojs/hono#4359</a></li>
<li>feat(proxy): add <code>customFetch</code> option to allow custom
fetch function by <a
href="https://github.com/yusukebe"><code>@​yusukebe</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/4360">honojs/hono#4360</a></li>
<li>chore: update <code>typescript</code> to <code>5.9.2</code> by <a
href="https://github.com/yusukebe"><code>@​yusukebe</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/4362">honojs/hono#4362</a></li>
<li>chore: add <code>packageManager</code> field to
<code>package.json</code> by <a
href="https://github.com/yusukebe"><code>@​yusukebe</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/4363">honojs/hono#4363</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/honojs/hono/compare/v4.9.2...v4.9.3">https://github.com/honojs/hono/compare/v4.9.2...v4.9.3</a></p>
<h2>v4.9.2</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/honojs/hono/commit/7f4311c010dbd15bd25e16551ecf58059887d105"><code>7f4311c</code></a>
4.9.6</li>
<li><a
href="https://github.com/honojs/hono/commit/1d79aedc3f82d8c9969b115fe61bc4bd705ec8de"><code>1d79aed</code></a>
Merge commit from fork</li>
<li><a
href="https://github.com/honojs/hono/commit/adecab1caeb2665c8da83a470de958566890d6ba"><code>adecab1</code></a>
chore(benchmarks): remove comment-out from router bench (<a
href="https://redirect.github.com/honojs/hono/issues/4387">#4387</a>)</li>
<li><a
href="https://github.com/honojs/hono/commit/b3d5b404291a71ec088c5f5c9d6f2940150fbb5b"><code>b3d5b40</code></a>
chore: update packages in the router bench (<a
href="https://redirect.github.com/honojs/hono/issues/4386">#4386</a>)</li>
<li><a
href="https://github.com/honojs/hono/commit/98cb9633174a9a1a5279c37ee2a262658c6af60c"><code>98cb963</code></a>
4.9.5</li>
<li><a
href="https://github.com/honojs/hono/commit/b3e8cab13da828f2af84fe6dcce6e2e8a156b85f"><code>b3e8cab</code></a>
fix(language-detector): Detect language from path after getPath changed
(<a
href="https://redirect.github.com/honojs/hono/issues/4369">#4369</a>)</li>
<li><a
href="https://github.com/honojs/hono/commit/0e3db674ad3f40be215a55a18062dd8e387ce525"><code>0e3db67</code></a>
fix(service-worker): correct args for <code>app.fetch</code> in
<code>handle</code> (<a
href="https://redirect.github.com/honojs/hono/issues/4374">#4374</a>)</li>
<li><a
href="https://github.com/honojs/hono/commit/c4577e93746c4642d5e663509febcb803d20f47e"><code>c4577e9</code></a>
fix(cors): Allow returning null or undefined for origin (<a
href="https://redirect.github.com/honojs/hono/issues/4375">#4375</a>)</li>
<li><a
href="https://github.com/honojs/hono/commit/5bfbff8acf54395174d54c65ad8d796493c2b7ea"><code>5bfbff8</code></a>
feat(cors): Allow async functions for <code>origin</code> and
<code>allowMethods</code> (<a
href="https://redirect.github.com/honojs/hono/issues/4373">#4373</a>)</li>
<li><a
href="https://github.com/honojs/hono/commit/a2685692543ceb0a4cfcc1e6a95f4f9cda73f14f"><code>a268569</code></a>
fix(aws-lambda): preserve percent-encoded values in query strings (<a
href="https://redirect.github.com/honojs/hono/issues/4372">#4372</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/honojs/hono/compare/v4.8.9...v4.9.6">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=hono&package-manager=npm_and_yarn&previous-version=4.8.9&new-version=4.9.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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-09-08 16:49:55 -04:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
50ce6badee chore: bump actions/setup-python from 5 to 6 (#6099)
Bumps [actions/setup-python](https://github.com/actions/setup-python)
from 5 to 6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/setup-python/releases">actions/setup-python's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.0</h2>
<h2>What's Changed</h2>
<h3>Breaking Changes</h3>
<ul>
<li>Upgrade to node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/1164">actions/setup-python#1164</a></li>
</ul>
<p>Make sure your runner is on version v2.327.1 or later to ensure
compatibility with this release. <a
href="https://github.com/actions/runner/releases/tag/v2.327.1">See
Release Notes</a></p>
<h3>Enhancements:</h3>
<ul>
<li>Add support for <code>pip-version</code> by <a
href="https://github.com/priyagupta108"><code>@​priyagupta108</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/1129">actions/setup-python#1129</a></li>
<li>Enhance reading from .python-version by <a
href="https://github.com/krystof-k"><code>@​krystof-k</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/787">actions/setup-python#787</a></li>
<li>Add version parsing from Pipfile by <a
href="https://github.com/aradkdj"><code>@​aradkdj</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/1067">actions/setup-python#1067</a></li>
</ul>
<h3>Bug fixes:</h3>
<ul>
<li>Clarify pythonLocation behaviour for PyPy and GraalPy in environment
variables by <a
href="https://github.com/aparnajyothi-y"><code>@​aparnajyothi-y</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/1183">actions/setup-python#1183</a></li>
<li>Change missing cache directory error to warning by <a
href="https://github.com/aparnajyothi-y"><code>@​aparnajyothi-y</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/1182">actions/setup-python#1182</a></li>
<li>Add Architecture-Specific PATH Management for Python with --user
Flag on Windows by <a
href="https://github.com/aparnajyothi-y"><code>@​aparnajyothi-y</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/1122">actions/setup-python#1122</a></li>
<li>Include python version in PyPy python-version output by <a
href="https://github.com/cdce8p"><code>@​cdce8p</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/1110">actions/setup-python#1110</a></li>
<li>Update docs: clarification on pip authentication with setup-python
by <a
href="https://github.com/priya-kinthali"><code>@​priya-kinthali</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/1156">actions/setup-python#1156</a></li>
</ul>
<h3>Dependency updates:</h3>
<ul>
<li>Upgrade idna from 2.9 to 3.7 in /<strong>tests</strong>/data by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-python/pull/843">actions/setup-python#843</a></li>
<li>Upgrade form-data to fix critical vulnerabilities <a
href="https://redirect.github.com/actions/setup-python/issues/182">#182</a>
&amp; <a
href="https://redirect.github.com/actions/setup-python/issues/183">#183</a>
by <a
href="https://github.com/aparnajyothi-y"><code>@​aparnajyothi-y</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/1163">actions/setup-python#1163</a></li>
<li>Upgrade setuptools to 78.1.1 to fix path traversal vulnerability in
PackageIndex.download by <a
href="https://github.com/aparnajyothi-y"><code>@​aparnajyothi-y</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/1165">actions/setup-python#1165</a></li>
<li>Upgrade actions/checkout from 4 to 5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-python/pull/1181">actions/setup-python#1181</a></li>
<li>Upgrade <code>@​actions/tool-cache</code> from 2.0.1 to 2.0.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-python/pull/1095">actions/setup-python#1095</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/krystof-k"><code>@​krystof-k</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-python/pull/787">actions/setup-python#787</a></li>
<li><a href="https://github.com/cdce8p"><code>@​cdce8p</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/setup-python/pull/1110">actions/setup-python#1110</a></li>
<li><a href="https://github.com/aradkdj"><code>@​aradkdj</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/setup-python/pull/1067">actions/setup-python#1067</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-python/compare/v5...v6.0.0">https://github.com/actions/setup-python/compare/v5...v6.0.0</a></p>
<h2>v5.6.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Workflow updates related to Ubuntu 20.04 by <a
href="https://github.com/aparnajyothi-y"><code>@​aparnajyothi-y</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/1065">actions/setup-python#1065</a></li>
<li>Fix for Candidate Not Iterable Error by <a
href="https://github.com/aparnajyothi-y"><code>@​aparnajyothi-y</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/1082">actions/setup-python#1082</a></li>
<li>Upgrade semver and <code>@​types/semver</code> by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/1091">actions/setup-python#1091</a></li>
<li>Upgrade prettier from 2.8.8 to 3.5.3 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/1046">actions/setup-python#1046</a></li>
<li>Upgrade ts-jest from 29.1.2 to 29.3.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/1081">actions/setup-python#1081</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-python/compare/v5...v5.6.0">https://github.com/actions/setup-python/compare/v5...v5.6.0</a></p>
<h2>v5.5.0</h2>
<h2>What's Changed</h2>
<h3>Enhancements:</h3>
<ul>
<li>Support free threaded Python versions like '3.13t' by <a
href="https://github.com/colesbury"><code>@​colesbury</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/973">actions/setup-python#973</a></li>
<li>Enhance Workflows: Include ubuntu-arm runners, Add e2e Testing for
free threaded and Upgrade <code>@​action/cache</code> from 4.0.0 to
4.0.3 by <a
href="https://github.com/priya-kinthali"><code>@​priya-kinthali</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/1056">actions/setup-python#1056</a></li>
<li>Add support for .tool-versions file in setup-python by <a
href="https://github.com/mahabaleshwars"><code>@​mahabaleshwars</code></a>
in <a
href="https://redirect.github.com/actions/setup-python/pull/1043">actions/setup-python#1043</a></li>
</ul>
<h3>Bug fixes:</h3>
<ul>
<li>Fix architecture for pypy on Linux ARM64 by <a
href="https://github.com/mayeut"><code>@​mayeut</code></a> in <a
href="https://redirect.github.com/actions/setup-python/pull/1011">actions/setup-python#1011</a>
This update maps arm64 to aarch64 for Linux ARM64 PyPy
installations.</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/setup-python/commit/e797f83bcb11b83ae66e0230d6156d7c80228e7c"><code>e797f83</code></a>
Upgrade to node 24 (<a
href="https://redirect.github.com/actions/setup-python/issues/1164">#1164</a>)</li>
<li><a
href="https://github.com/actions/setup-python/commit/3d1e2d2ca0a067f27da6fec484fce7f5256def85"><code>3d1e2d2</code></a>
Revert &quot;Enhance cache-dependency-path handling to support files
outside the w...</li>
<li><a
href="https://github.com/actions/setup-python/commit/65b071217a8539818fdb8b54561bcbae40380a54"><code>65b0712</code></a>
Clarify pythonLocation behavior for PyPy and GraalPy in environment
variables...</li>
<li><a
href="https://github.com/actions/setup-python/commit/5b668cf7652160527499ee14ceaff4be9306cb88"><code>5b668cf</code></a>
Bump actions/checkout from 4 to 5 (<a
href="https://redirect.github.com/actions/setup-python/issues/1181">#1181</a>)</li>
<li><a
href="https://github.com/actions/setup-python/commit/f62a0e252fe7114e86949abfa6e1e89f85bb38c2"><code>f62a0e2</code></a>
Change missing cache directory error to warning (<a
href="https://redirect.github.com/actions/setup-python/issues/1182">#1182</a>)</li>
<li><a
href="https://github.com/actions/setup-python/commit/9322b3ca74000aeb2c01eb777b646334015ddd72"><code>9322b3c</code></a>
Upgrade setuptools to 78.1.1 to fix path traversal vulnerability in
PackageIn...</li>
<li><a
href="https://github.com/actions/setup-python/commit/fbeb884f69f0ac1c0257302f62aa524c2824b649"><code>fbeb884</code></a>
Bump form-data to fix critical vulnerabilities <a
href="https://redirect.github.com/actions/setup-python/issues/182">#182</a>
&amp; <a
href="https://redirect.github.com/actions/setup-python/issues/183">#183</a>
(<a
href="https://redirect.github.com/actions/setup-python/issues/1163">#1163</a>)</li>
<li><a
href="https://github.com/actions/setup-python/commit/03bb6152f4f691b9d64579a1bd791904a083c452"><code>03bb615</code></a>
Bump idna from 2.9 to 3.7 in /<strong>tests</strong>/data (<a
href="https://redirect.github.com/actions/setup-python/issues/843">#843</a>)</li>
<li><a
href="https://github.com/actions/setup-python/commit/36da51d563b70a972897150555bb025096d65565"><code>36da51d</code></a>
Add version parsing from Pipfile (<a
href="https://redirect.github.com/actions/setup-python/issues/1067">#1067</a>)</li>
<li><a
href="https://github.com/actions/setup-python/commit/3c6f142cc0036d53007e92fa1e327564a4cfb7aa"><code>3c6f142</code></a>
update documentation (<a
href="https://redirect.github.com/actions/setup-python/issues/1156">#1156</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/setup-python/compare/v5...v6">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/setup-python&package-manager=github_actions&previous-version=5&new-version=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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-08 16:49:17 -04:00
Sydney RunkleandGitHub 6fc5b3aeda release(langgraph): 0.6.7 (#6092) 2025-09-07 13:49:43 +00:00
Harrison ChaseandGitHub b543752878 chore: update emphemeral local (#6091)
basically - for conditional edges, we use this to merge the updates from
state with the state object (before the actual update really occurs in
the tick.after)

otherwise - an emphemeral value will actually last through the logic in
the conditional edge of the node after
2025-09-07 09:42:11 -04:00
William FHandGitHub 8f6ad0b25a chore(sdk-py): Cleanup docstring indentation (#6087) 2025-09-05 22:56:03 +00:00
Isaac FranciscoandGitHub ada5d2ecb1 feat(cli): bump version (#6086)
version bump for: https://github.com/langchain-ai/langgraph/pull/6085
2025-09-05 15:52:30 -07:00
Isaac FranciscoandGitHub eaeafe54ab feat(cli): support prereleases (#6085)
We previously errored when a user had prerelease dependencies, this PR
passes the `--prereleases=allow` flag to our `uv pip install` call.

This PR also adds a test to verify that said deployments will build and
run as expected.
2025-09-05 15:45:48 -07:00
William FHandGitHub f761116de7 chore(sdk-py): Clean up docstring for get_client (#6084)
Main thing here is to call out the ASGITransport behavior
2025-09-05 13:43:31 -07:00
Nuno CamposandGitHub 36cf353d19 fix: Unwrap Required/NotRequired special forms before resolving channel/reducer annotations (#6080) 2025-09-05 10:27:10 +01:00
d503c0bf33 WIP: monorepo support in CLI (#6028)
This PR introduces the `--build-command` and `--install-command`
arguments to `langgraph build`.

`--install-command` is a custom install command. If passed, it will be
run from wherever the `langgraph build` call was made, i.e. NOT where
the langgraph.json file lives (except if these are the same place). This
will override the detected install command that we previously used.

`--build-command` is a custom build command. This will run from wherever
the langgraph.json file lives, and will be done after the install has
been run.

You don't need to provide both. Just providing one will make the install
(detected or supplied) run in the directory from where `langgraph build
was called` and then have the build command (if one exists) run in the
directory where langgraph.json exists.

I think we should probably allow configuring the directories from which
these commands get run, but I don't think this needs to be part of the
MVP.

---------

Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com>
2025-09-04 12:29:11 -07:00
William FHandGitHub 25ba4c3bda feat(sdk-py): Specify ttl on thread creation and update (#6075) 2025-09-03 18:48:57 -07:00
dfc1c59ebf chore(docs): Update OpenAPI spec from LangGraph API v0.4.11 (#6074)
This PR updates the OpenAPI specification with changes detected from the
LangGraph API server.

**Changes detected as of LangGraph API version 0.4.11**

This update was automatically generated by the sync workflow in the
langgraph-api repository.

Co-authored-by: hinthornw <hinthornw@users.noreply.github.com>
2025-09-03 18:37:39 -07:00
William FHandGitHub 6f4c5fefee feat(sdk-py): Support ids filtering in threads search (#6067) 2025-09-02 17:49:11 -07:00
7cf230defa chore(docs): Update OpenAPI spec from LangGraph API v0.4.9 (#6066)
This PR updates the OpenAPI specification with changes detected from the
LangGraph API server.

**Changes detected as of LangGraph API version 0.4.9**

This update was automatically generated by the sync workflow in the
langgraph-api repository.

Co-authored-by: hinthornw <hinthornw@users.noreply.github.com>
2025-09-02 17:04:30 -07:00
5db65e0281 chore(docs): Update OpenAPI spec from LangGraph API v0.4.8 (#6065)
This PR updates the OpenAPI specification with changes detected from the
LangGraph API server.

**Changes detected as of LangGraph API version 0.4.8**

This update was automatically generated by the sync workflow in the
langgraph-api repository.

Co-authored-by: hinthornw <hinthornw@users.noreply.github.com>
2025-09-02 15:25:52 -07:00
b08c2e092f chore(docs): Update OpenAPI spec from LangGraph API v0.4.8 (#6048)
This PR updates the OpenAPI specification with changes detected from the
LangGraph API server.

**Changes detected as of LangGraph API version 0.4.8**

This update was automatically generated by the sync workflow in the
langgraph-api repository.

Co-authored-by: hinthornw <hinthornw@users.noreply.github.com>
2025-09-02 10:10:12 -07:00
Sydney RunkleandGitHub 120ae38c12 chore(docs): fix runtime context link (#6043) 2025-08-29 13:45:39 -04:00
Isaac FranciscoandGitHub 22942d4eec release(sdk-py): 0.2.4 (#6038) 2025-08-28 23:34:33 +00:00
Isaac FranciscoandGitHub 1756ce1dd2 feat(sdk-py): add endpoint for thread streaming (#6009)
SDK support for:
https://github.com/langchain-ai/langgraph-api/pull/1217/
2025-08-28 16:12:04 +00:00
Isaac FranciscoandGitHub 0b4638269b feat(sdk-py): add durability flag (#5963) 2025-08-27 19:21:25 +00:00
Isaac FranciscoandGitHub 1ebdb1ba31 chore: Update schema for new config allowed in LGP (#5875) 2025-08-27 11:20:06 -07:00
hari-dhanushkodiandGitHub f3423c052e fix(docs): add revision queuing docs (#5997) 2025-08-27 07:47:45 -07:00
b63572ee16 chore: Update OpenAPI spec from LangGraph API v0.4.0 (#6011)
This PR updates the OpenAPI specification with changes detected from the
LangGraph API server.

**Changes detected as of LangGraph API version 0.4.0**

This update was automatically generated by the sync workflow in the
langgraph-api repository.

Co-authored-by: hinthornw <hinthornw@users.noreply.github.com>
2025-08-26 20:51:30 -07:00
William FHandGitHub ddf4e62bde release(cli): 0.4.0 (#6014)
Relax upper-bound to permit server versions 0.4.*
2025-08-26 12:59:12 +00:00
William FHandGitHub d73902ae76 feat(sdk-py): Count endpoints (#5986) 2025-08-21 18:15:52 +00:00
William FHandGitHub 501ba8be34 release(cli): Bump max bound of langgraph-api (#5978) 2025-08-21 00:59:27 +00:00
William FHandGitHub 998e194e82 release(cli): Support bookworm, trixie, etc. (#5975)
Also add support for pinning to a semantic version.
2025-08-20 15:40:04 +00:00
ef65d3cf88 chore(cli): Update OpenAPI spec from LangGraph API v0.2.137 (#5967)
This PR updates the OpenAPI specification with changes detected from the
LangGraph API server.

**Changes detected as of LangGraph API version 0.2.137**

This update was automatically generated by the sync workflow in the
langgraph-api repository.

Co-authored-by: hinthornw <hinthornw@users.noreply.github.com>
2025-08-20 07:42:33 -07:00
William FHandGitHub a692e24a58 fix(langgraph): Remote Baggage (#5964)
Fix baggage propagation for opt-in distributed tracing when no
additional headers are provided.
2025-08-20 01:47:12 +00:00
BrodyandGitHub a566f1f892 fix(docs): update sales links (#5956)
**Description:** updates sales team links to point to our form.
  
**Issue:** DOC-170 (internal Linear ticket)
2025-08-19 08:11:51 -07:00
William FHandGitHub c0b29a6df5 chore(langgraph): Add passthrough params/headers to invoke/stream/etc. (#5940) 2025-08-18 19:38:08 +00:00
Ankit R.andGitHub a86eb4c5d0 docs(persistence): fix StateSnapshot formatting (#5928)
This PR fixes a minor formatting inconsistency in the StateSnapshot
examples within persistence.md.

Specifically, the next=('node_b',) value was inline with values={...},
which is inconsistent with other snapshots.
It has been moved to a new line for better readability and consistency
across examples.
2025-08-18 19:33:43 +00:00
William FHandGitHub 3488eb2a2c chore(sdk-py): Update types (#5939) 2025-08-18 18:29:07 +00:00
wakita181009andGitHub 875f20ba9f feat(sdk-py): define aclose method to LangGraphClient (#5931)
This PR adds an aclose method to the LangGraphClient.

When using the client in a FastAPI application, it's common to share a
single instance across the application's lifespan. The absence of an
aclose method makes it difficult to gracefully close the underlying HTTP
session on application shutdown. This change enables proper resource
management by allowing the client to be closed cleanly.
2025-08-18 11:22:02 -07:00
William FHandGitHub 723d4641b0 chore(sdk-py): Update params type in SDK (#5937) 2025-08-18 17:53:20 +00:00
William FHandGitHub ae62b8faf2 chore: Update release check of version (#5936) 2025-08-18 10:18:53 -07:00
William FHandGitHub 9918488169 feat(sdk-py): client qparams (#5918)
And add linting & dyanmic version string
2025-08-18 10:05:24 -07:00
Lauren Hirata SinghandGitHub c37c9cbab3 docs: update redirects (#5935) 2025-08-18 09:14:49 -07:00
William FHandGitHub 0cd8745aad feat(sdk-py): Select-statement (#5933) 2025-08-18 06:42:01 -07:00
Lauren Hirata SinghandGitHub 33d13c6f52 docs: update banner (#5911) 2025-08-14 10:54:18 -07:00
Lauren Hirata SinghandGitHub 054e2759ca docs: banner for deep research (#5908)
Publish at 10AM PT
2025-08-14 10:04:48 -07:00
William FHandGitHub 23b71048c1 release(langgraph): 0.6.5 (#5901) 2025-08-13 23:35:58 +00:00
Nuno CamposandGitHub a15f542a1f fix: Persist resume_map values (#5898)
Thank you for contributing to LangGraph! Follow these steps to mark your
pull request as ready for review. **If any of these steps are not
completed, your PR will not be considered for review.**

- [ ] **PR title**: Follows the format: {TYPE}({SCOPE}): {DESCRIPTION}
  - Examples:
    - feat(core): add multi-tenant support
    - fix(cli): resolve flag parsing error
    - docs(openai): update API usage examples
  - Allowed `{TYPE}` values:
- feat, fix, docs, style, refactor, perf, test, build, ci, chore,
revert, release
  - Allowed `{SCOPE}` values (optional):
- langgraph, docs, cli, checkpoint, checkpoint-postgres,
checkpoint-sqlite, prebuilt, scheduler-kafka, sdk-py
- Once you've written the title, please delete this checklist item; do
not include it in the PR.

- [ ] **PR message**: ***Delete this entire checklist*** and replace
with
- **Description:** a description of the change. Include a [closing
keyword](https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword)
if applicable.
  - **Issue:** the issue # it fixes, if applicable
  - **Dependencies:** any dependencies required for this change
- **Twitter handle:** if your PR gets announced, and you'd like a
mention, we'll gladly shout you out!

- [ ] **Add tests and docs**: If you're adding a new integration, you
must include:
1. A test for the integration, preferably unit tests that do not rely on
network access,
2. An example notebook showing its use. It lives in
`docs/docs/integrations` directory.

- [ ] **Lint and test**: Run `make format`, `make lint` and `make test`
from the root of the package(s) you've modified. We will not consider a
PR unless these three are passing in CI. See [contribution
guidelines](https://github.com/langchain-ai/langgraph/blob/main/CONTRIBUTING.md)
for more.

Additional guidelines:

- Make sure optional dependencies are imported within a function.
- Please do not add dependencies to `pyproject.toml` files (even
optional ones) unless they are **required** for unit tests.
- Most PRs should not touch more than one package.
- Changes should be backwards compatible.
2025-08-13 19:33:20 +01:00
d43eaf1f42 chore(docs): add remaining js translations (#5825)
Related Linear ticket:
https://linear.app/langchain/issue/DOC-51/add-js-translations-for-remaining-pages

---------

Co-authored-by: Brody Klapko <brody@langchain.dev>
2025-08-12 09:47:11 -04:00
Sam CrowderandGitHub 16b363fbb0 feat(langgraph): implement redis node level cache (#5834)
###   Description

Adds Redis as a supported cache backend for LangGraph node-level
caching, enabling distributed caching across multiple processes/servers.
This implementation follows the same patterns as existing InMemoryCache
and SqliteCache.

###  Key changes
  - New RedisCache class implementing the BaseCache interface
  - Support for TTL-based expiration and batch operations
  - Worker-specific cache prefixes for parallel test isolation

###  Dependencies

  - redis package (already included in dev dependencies)

### Test Plan

- Unit tests: Added Redis cache tests covering basic operations, TTL,
batch operations, and error handling
- Integration tests: Redis cache integrated into existing LangGraph test
suite, tested with all checkpointer combinations
2025-08-11 09:19:34 -07:00
Sydney RunkleandGitHub 68a75135b0 release: langgraph + prebuilt 0.6.4 (#5854) 2025-08-07 18:12:26 +00:00
Isaac FranciscoandGitHub 5c0c0fb186 fix: mypy issue with conditional edges (#5851)
Send should inherit from hashable, and need to use Sequence since List
is invariant.

https://github.com/langchain-ai/langgraph/issues/5850
2025-08-07 08:46:44 -07:00
4571b708d9 fix(langgraph): support emitting messages from subgraphs when messages mode explicitly requested (#5836)
Reproduces:
https://github.com/langchain-ai/langgraph/issues/5249#issuecomment-3156519635
Caused after this change:
https://github.com/langchain-ai/langgraph/pull/4843

Fix to allow emitting messages from subgraphs if the subgraphs
explicitly used a stream mode "messages".

```python

def node_in_parent(...):
   # subgraph was called as a function.
   # messages are explicitly requested.
   for event in subgraph.stream(..., stream_mode="messages"):
      # something is done with `event`
   return ...

# subgraphs = False!
parent_graph.invoke(..., subgraphs=False)
```

The code above should continue to work correctly regardless of the value
of subgraphs as streaming messages was requested explicitly in the
parent node!

---------

Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-08-07 10:10:52 -04:00
Sydney RunkleandGitHub e365b2b8bd fix(prebuilt): raise on additional deprecated kwargs (#5848) 2025-08-06 21:08:42 +00:00
Isaac FranciscoandGitHub b5504506a7 fix: add resiliency for task cancellation (#5846) 2025-08-06 13:31:52 -07:00
Nuno CamposandGitHub c6ae8d25b9 perf: Save updated_channels to checkpoint (#5828)
- This makes prepare_next_tasks constant on number of nodes in all
cases, whereas before we were falling back to node iteration when
resuming from an existing checkpoint
2025-08-06 19:09:33 +01:00
Sydney RunkleandGitHub 0bd7dd2c52 chore(langgraph): deprecate MessageGraph (#5843)
`MessageGraph` is deprecated, to be removed in v2.

A `StateGraph` with a `messages` key should be used instead.
Alternatively, folks can use `Annotated[list[AnyMessage], add_messages]` as their state schema.
2025-08-06 14:17:50 +00:00
Sydney RunkleandGitHub 82978a8dd8 chore(prebuilt): revert tool arg injection refactor (#5842)
Reverts https://github.com/langchain-ai/langgraph/pull/5562

I anticipate that we want to do another pass at a refactor here in the
short term, but this makes it easier to adapt to new langchain core
message types for v0.4 support in the short term.
2025-08-06 10:12:08 -04:00
Kathryn MayandGitHub 925150a35d docs: Update redirects for deployment option renaming (#5823)
Updates the URLs for the new site deployment options after a rename.
2025-08-04 15:32:11 -04:00
Sydney RunkleandGitHub 2920a9dd19 fix(langgraph): Tidy up AgentState (#5801)
Fixes https://github.com/langchain-ai/langgraph/issues/5784

* Removes usage of `is_last_step`, no longer needed with
`remaining_steps`
* Make `remaining_steps` `NotRequired` so that json schema doesn't
suggest need for user input
* Move `PregelScratchpad` to shared utils file to prevent circular
import issue (it's used from `channels/managed` and other pregel files).
* Ensures that managed values wrapped in `NotRequired` or `Required` are
still recognized!
2025-08-03 07:12:53 -04:00
Eugene YurtsevandGitHub db8ed4e9e4 fix(docs): update agents.md (#5800)
fix comment in tip
2025-08-02 06:09:09 -04:00
Lauren Hirata SinghandGitHub b16fcc8468 docs: remove broken links (#5803) 2025-08-01 15:41:21 -04:00
Sydney RunkleandGitHub a2fe4df89b release: langgraph + prebuilt 0.6.3 (#5799) 2025-08-01 14:52:38 -04:00
open-swe[bot]GitHubopen-swe[bot] <open-swe@users.noreply.github.com>Sydney Runkle
69dd20e523 fix(langgraph): Add warning for incorrect node signature with mistyped config param (#5798)
Fixes: #5787

Ensures that if `config` is not typed as one of `RunanbleConfig` or
`Optional[RunnableConfig]` a warning is raised to help developers avoid
unexpected results at invocation time.

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Sydney Runkle <sydneymarierunkle@gmail.com>
2025-08-01 17:25:14 +00:00
open-swe[bot]GitHubopen-swe[bot] <open-swe@users.noreply.github.com>
5152a96fce fix(docs): Correct import statement for InMemorySaver in conceptual docs (#5797)
Fixes #5781

Fixes the incorrect import statement in the Python documentation
tutorial.

- Changed import from `MemorySaver` to `InMemorySaver`
- Ensures consistency between import statement and class instantiation
- Verified through formatting and linting checks

The documentation now correctly reflects the proper import for the
InMemorySaver class.

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2025-08-01 14:54:30 +00:00
Sydney RunkleandGitHub 220314b53a fix(langgraph): fix up deprecation warnings (#5796)
Fixes https://github.com/langchain-ai/langgraph/issues/5795

* Must use `category=None` on decorator so that we get type checking
support but no dupe warning
* Fixed tuple on `confix_type` warning causing false warning
2025-08-01 14:33:46 +00:00
38bbd92e01 feat(langgraph): add durability mode for invoke and ainvoke (#5771)
Fixes https://github.com/langchain-ai/langgraph/issues/5741

Follow up to https://github.com/langchain-ai/langgraph/pull/5432

Plus clean up deprecation logic for `checkpoint_during` and add tests.

---------

Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
2025-08-01 10:30:24 -04:00
Eugene YurtsevandGitHub e3cb2dd23b chore(docs): fix more admonitions (#5792)
Fix more admonitions
2025-07-31 22:57:44 -04:00
Eugene YurtsevandGitHub 2f23d1a30d chore(docs): fix js build (#5793)
Fix js build
2025-07-31 22:57:32 -04:00
Eugene YurtsevandGitHub 88e195bb78 chore(docs): fix admonitions in graph api page (#5791)
fix many admonitions in the graph API page
2025-07-31 21:50:27 -04:00
41a4f993b1 docs: Update link maps for reference docs (#5745)
Update link maps

---------

Co-authored-by: Hunter Lovell <hunter@hntrl.io>
2025-07-31 18:06:35 -04:00
b8f3f48da9 fix(docs): Add missing imports to make examples runnable (#5477)
I suppose that the code snippets are intended to run each on its own. To
guarantee this the snippet for the example:
"Write long-temr memory from tools"
needs to include `RunnableConfig`
Same also for the second commit of this pull request.

The other commits are about similar issues, where imports are missing to
make a snippet executable on its own.

---------

Signed-off-by: Kai Wendel <kai.wendel@iws.uni-stuttgart.de>
Co-authored-by: Eugene Yurtsev <eugene@langchain.dev>
Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
2025-07-31 20:04:52 +00:00
94f7f0632d docs(docs): fix image in "Run graph nodes in parallel" section of N Graph API how-to (#5527)
**Description:**
Replaced the outdated image in the "Run graph nodes in parallel" section
of the N Graph API how-to guide to correctly show parallel node
execution.

**Twitter handle:** @MichaelLoukeris

Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
2025-07-31 20:02:33 +00:00
Xin JinandGitHub b3e0582255 docs: clarify draw_mermaid_png only works in jupyter (#5609)
Nit, without comments I thought image would somehow show in terminal,
but that's not true you'd only get image to show if in jupyter notebook.
Don't have to merge, i'm just seeing this particular as not a pleasure
DevX.

<img width="848" height="440" alt="Screenshot 2025-07-21 at 12 26 04 PM"
src="https://github.com/user-attachments/assets/50261b35-f09d-4516-86f4-14e8bf53f8e2"
/>
2025-07-31 15:54:45 -04:00
24c7a8db3f Remove duplicated pretty_print_messages helper in Multi‑agent supervisor tutorial (#5617)
**Description:**  
Closes #___

Removed the redundant `pretty_print_message`/`pretty_print_messages`
helper snippet from
`docs/docs/tutorials/multi_agent/agent_supervisor.md`. Now there is a
single, authoritative definition of these functions, which:

- Simplifies the tutorial  
- Avoids reader confusion over which helper to use  
- Prevents future drift between duplicate code blocks  

**Issue:** Closes #___  
**Dependencies:** None

Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
2025-07-31 19:54:22 +00:00
f8eb4244e0 docs(graphapi): update the graph image for the "Combine control flow and state updates with Command" example (#5626)
The example had the node names as - node_a, node_b & node_c. But the
graph shows the image of generate_topics. This change includes the
addition of complete & accurate graph.

---------

Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
2025-07-31 19:52:55 +00:00
Syed Baqar AbbasandGitHub 62c3bbc9fe docs: Removed repetition of block pretty_print_messages (#5636)
## docs: Removed repetition of block pretty_print_messages
- **Description:** The documentation had the same cell duplicated, I
fixed it by deleting one example
  - **Issue:** #5616
2025-07-31 19:49:48 +00:00
Kathryn MayandGitHub 76bbb761b4 docs: Add studio troubleshooting to redirects (#5783)
Add a redirect from
https://langchain-ai.github.io/langgraph/troubleshooting/studio/ to
https://docs.langchain.com/langgraph-platform/troubleshooting-studio
2025-07-31 15:31:35 -04:00
Sydney RunkleandGitHub 80cd91344f chore: no ci on v1 branch (#5782) 2025-07-31 19:08:10 +00:00
Lauren Hirata SinghandGitHub 9e4c41cbed docs: remove LGP mentions (#5780) 2025-07-31 14:13:56 -04:00
ShehabandGitHub 1fda568df9 fix(docs): extended examples in graph API docs (#5774)
Fixes #5770
2025-07-31 18:00:54 +00:00
08295ecadb chore(prebuilt): add supported input types for model in create_react_agent (#5748)
- **Description:** Update the type annotations in create_react_agent to
allow one to provide a callable for the model that uses bind_tools and
returns a Runnable[LanguageModelInput, BaseMessage]
  - **Issue:** #5739

---------

Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
2025-07-31 14:00:12 -04:00
Lauren Hirata SinghandGitHub 4ecbabafe8 docs: redirects for LGP mintlify (#5767)
- Added redirects for all of the LGP docs we're moving to Mintlify
- Exclude files not listed in nav from search
- Update banner
2025-07-31 13:10:45 -04:00
Sam CrowderandGitHub 246efe71f4 fix: change from developer to enterprise (#5778) 2025-07-31 09:42:19 -07:00
Eugene YurtsevandGitHub 116121eb3a feat(docs): dynamic model and tool selection in create react agent (#5777)
Document dynamic models and dynamic tools
2025-07-31 11:22:30 -04:00
William FHandGitHub 18887e9f86 fix(langgraph): Remove duplicate call to ensure_config (#5768) 2025-07-31 09:15:03 -04:00
Sam CrowderandGitHub bec28226d0 fix: removing standalone container lite from old docs (#5759) 2025-07-30 18:21:37 -07:00
Sam CrowderandGitHub 967e368e14 fix: add link that points to where changelog now lives (#5758) 2025-07-30 17:49:51 -07:00
Lauren Hirata SinghandGitHub 9d4dd066e5 docs: Revert "docs: Delete LGP nav Items from docs" (#5753)
Reverts langchain-ai/langgraph#5743
2025-07-30 18:15:19 -04:00
Lauren Hirata SinghandGitHub 81027b2b80 docs: fix redirects to external pages (#5752) 2025-07-30 16:52:13 -04:00
Sydney RunkleandGitHub 296bf5f75e fix(docs): context docs formatting (#5751) 2025-07-30 16:41:49 -04:00
414 changed files with 52194 additions and 11579 deletions
+5 -5
View File
@@ -1,21 +1,21 @@
name: "\U0001F41B Bug Report"
description: Report a bug in LangGraph. To report a security issue, please instead use the security option below. For questions, please use the LangChain Forum at forum.langchain.com.
labels: [pending,bug]
labels: [pending, bug]
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to file a bug report.
Use this to report BUGS in LangGraph. For usage questions, feature requests and general design questions, please use the [LangChain Forum](https://forum.langchain.com/).
Relevant links to check before filing a bug report to see if your issue has already been reported, fixed or
if there's another way to solve your problem:
* [LangChain Forum](https://forum.langchain.com/),
* [LangGraph Github Issues](https://github.com/langchain-ai/langgraph/issues),
* [LangGraph how-to guides](https://langchain-ai.github.io/langgraph/how-tos/).
* [LangChain documentation with the integrated search](https://python.langchain.com/docs/get_started/introduction),
* [LangChain documentation with the integrated search](https://docs.langchain.com/),
* [GitHub search](https://github.com/langchain-ai/langgraph),
- type: checkboxes
id: checks
+4 -1
View File
@@ -1,6 +1,9 @@
blank_issues_enabled: false
version: 2.1
contact_links:
- name: Documentation
url: https://github.com/langchain-ai/docs/issues/new?template=langgraph.yml
about: Report an issue related to the LangGraph documentation
- name: LangChain Forum
url: https://forum.langchain.com/
about: General community discussions, support, and feature requests
about: General community discussions and support
-19
View File
@@ -1,19 +0,0 @@
name: Documentation
description: Report an issue related to the LangGraph documentation.
title: "DOC: <Please write a comprehensive title after the 'DOC: ' prefix>"
labels: [documentation]
body:
- type: textarea
attributes:
label: "Issue with current documentation:"
description: >
Please make sure to leave a reference to the document/code you're
referring to.
- type: textarea
attributes:
label: "Idea or request for content:"
description: >
Please describe as clearly as possible what topics you think are missing
from the current documentation.
+8 -3
View File
@@ -1,10 +1,15 @@
import ast
import os
from itertools import filterfalse
from typing import List, Tuple
from typing import Dict, List, Tuple
ROOT_PATH = os.path.abspath(os.path.join(__file__, "..", "..", ".."))
CLIENT_PATH = os.path.join(ROOT_PATH, "libs", "sdk-py", "langgraph_sdk", "client.py")
ASYNC_TO_SYNC_METHOD_MAP: Dict[str, str] = {
"aclose": "close",
"__aenter__": "__enter__",
"__aexit__": "__exit__",
}
def get_class_methods(node: ast.ClassDef) -> List[str]:
@@ -22,7 +27,7 @@ def find_classes(tree: ast.AST) -> List[Tuple[str, List[str]]]:
def compare_sync_async_methods(sync_methods: List[str], async_methods: List[str]) -> List[str]:
sync_set = set(sync_methods)
async_set = set(async_methods)
async_set = {ASYNC_TO_SYNC_METHOD_MAP.get(async_method, async_method) for async_method in async_methods}
missing_in_sync = list(async_set - sync_set)
missing_in_async = list(sync_set - async_set)
return missing_in_sync + missing_in_async
@@ -33,7 +38,7 @@ def main():
tree = ast.parse(file.read())
classes = find_classes(tree)
def is_sync(class_spec: Tuple[str, List[str]]) -> bool:
return class_spec[0].startswith("Sync")
+149 -87
View File
@@ -1,108 +1,164 @@
import asyncio
import json
import os
import logging
import pathlib
import sys
import langgraph_cli
import langgraph_cli.docker
import langgraph_cli.config
import time
from urllib import error, request
import langgraph_cli
import langgraph_cli.config
import langgraph_cli.docker
from langgraph_cli.cli import prepare_args_and_stdin
from langgraph_cli.constants import DEFAULT_PORT
from langgraph_cli.exec import Runner, subp_exec
from langgraph_cli.progress import Progress
from langgraph_cli.constants import DEFAULT_PORT
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
def test(
config: pathlib.Path,
port: int,
tag: str,
verbose: bool,
):
def test(config: pathlib.Path, port: int, tag: str, verbose: bool):
"""Spin up API with Postgres/Redis via docker compose and wait until ready."""
logger.info("Starting test...")
with Runner() as runner, Progress(message="Pulling...") as set:
# check docker available
# Detect docker/compose capabilities
capabilities = langgraph_cli.docker.check_capabilities(runner)
# open config
# Validate config and prepare compose stdin/args using built image
config_json = langgraph_cli.config.validate_config_file(config)
args, stdin = prepare_args_and_stdin(
capabilities=capabilities,
config_path=config,
config=config_json,
docker_compose=None,
port=port,
watch=False,
debugger_port=None,
debugger_base_url=f"http://127.0.0.1:{port}",
postgres_uri=None,
api_version=None,
image=tag,
base_image=None,
)
set("Running...")
args = [
"run",
"--rm",
"-p",
f"{port}:8000",
]
if isinstance(config_json["env"], str):
args.extend(
[
"--env-file",
str(config.parent / config_json["env"]),
]
)
else:
for k, v in config_json["env"].items():
args.extend(
[
"-e",
f"{k}={v}",
]
)
if capabilities.healthcheck_start_interval:
args.extend(
[
"--health-interval",
"5s",
"--health-retries",
"1",
"--health-start-period",
"10s",
"--health-start-interval",
"1s",
]
)
else:
args.extend(
[
"--health-interval",
"5s",
"--health-retries",
"2",
]
)
# Compose up with wait (implies detach), similar to `langgraph up --wait`
args_up = [*args, "up", "--remove-orphans", "--wait"]
_task = None
def on_stdout(line: str):
nonlocal _task
if "GET /ok" in line or "Uvicorn running on" in line:
set("")
sys.stdout.write(
f"""Ready!
- API: http://localhost:{port}
"""
)
sys.stdout.flush()
_task.cancel()
return True
return False
async def subp_exec_task(*args, **kwargs):
nonlocal _task
_task = asyncio.create_task(subp_exec(*args, **kwargs))
await _task
compose_cmd = ["docker", "compose"]
if capabilities.compose_type == "standalone":
compose_cmd = ["docker-compose"]
set("Starting...")
try:
runner.run(
subp_exec_task(
"docker",
*args,
tag,
subp_exec(
*compose_cmd,
*args_up,
input=stdin,
verbose=verbose,
on_stdout=on_stdout,
)
)
except asyncio.CancelledError:
except Exception as e: # noqa: BLE001
# On failure, show diagnostics then ensure clean teardown
sys.stderr.write(f"docker compose up failed: {e}\n")
try:
sys.stderr.write("\n== docker compose ps ==\n")
runner.run(
subp_exec(*compose_cmd, *args, "ps", input=stdin, verbose=False)
)
except Exception:
pass
try:
sys.stderr.write("\n== docker compose logs (api) ==\n")
runner.run(
subp_exec(
*compose_cmd,
*args,
"logs",
"langgraph-api",
input=stdin,
verbose=False,
)
)
except Exception:
pass
finally:
try:
runner.run(
subp_exec(
*compose_cmd,
*args,
"down",
"-v",
"--remove-orphans",
input=stdin,
verbose=False,
)
)
finally:
raise
set("")
base_url = f"http://localhost:{port}"
ok_url = f"{base_url}/ok"
logger.info(f"Waiting for {ok_url} to respond with 200...")
deadline = time.time() + 30
last_err: Exception | None = None
while time.time() < deadline:
try:
with request.urlopen(ok_url, timeout=2) as resp:
if resp.status == 200:
sys.stdout.write(
f"""Ready!\n- API: {base_url}\n- /ok: 200 OK\n"""
)
sys.stdout.flush()
break
else:
last_err = RuntimeError(f"Unexpected status: {resp.status}")
logger.error(f"Unexpected status: {resp.status}")
except error.URLError as e:
logger.error(f"URLError: {e}")
last_err = e
except Exception as e: # noqa: BLE001
logger.error(f"Exception: {e}")
last_err = e
time.sleep(0.5)
else:
logger.error("Timeout waiting for /ok to return 200")
# Bring stack down before raising
args_down = [*args, "down", "-v", "--remove-orphans"]
try:
runner.run(
subp_exec(
*compose_cmd,
*args_down,
input=stdin,
verbose=verbose,
)
)
finally:
raise SystemExit(
f"/ok did not return 202 within timeout. Last error: {last_err}"
)
# Clean up: bring compose stack down to free ports for next test
logger.info("Test succeeded. Bringing down compose stack...")
try:
args_down = [*args, "down", "-v", "--remove-orphans"]
runner.run(
subp_exec(
*compose_cmd,
*args_down,
input=stdin,
verbose=verbose,
)
)
logger.info("Compose stack down. Finishing...")
except Exception:
logger.exception("Failed to bring down compose stack")
pass
logger.info("Test finished")
if __name__ == "__main__":
import argparse
@@ -110,6 +166,12 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-t", "--tag", type=str)
parser.add_argument("-c", "--config", type=str, default="./langgraph.json")
parser.add_argument("-p", "--port", default=DEFAULT_PORT)
parser.add_argument("-p", "--port", type=int, default=DEFAULT_PORT)
args = parser.parse_args()
test(pathlib.Path(args.config), args.port, args.tag, verbose=True)
try:
test(pathlib.Path(args.config), args.port, args.tag, verbose=True)
except BaseException:
logger.exception("Test failed")
raise
logger.info("Test execution finished")
+76 -32
View File
@@ -13,13 +13,26 @@ jobs:
matrix:
python-version:
- "3.10"
- "3.11"
- "3.14"
example:
- name: A
workdir: libs/cli/examples
tag: langgraph-test-a
- name: B
workdir: libs/cli/examples/graphs
tag: langgraph-test-b
- name: C
workdir: libs/cli/examples/graphs_reqs_a
tag: langgraph-test-c
- name: D
workdir: libs/cli/examples/graphs_reqs_b
tag: langgraph-test-d
name: "CLI integration test"
defaults:
run:
working-directory: libs/cli
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Get changed files
id: changed-files
uses: Ana06/get-changed-files@v2.3.0
@@ -27,48 +40,79 @@ jobs:
filter: "libs/cli/**"
- name: Set up Python ${{ matrix.python-version }}
if: steps.changed-files.outputs.all
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ matrix.python-version }}
enable-cache: true
cache-suffix: "cli-integration-test"
ignore-nothing-to-cache: true
- name: Setup env
if: steps.changed-files.outputs.all
working-directory: libs/cli/examples
run: cat .env.example > .env
- name: Install cli globally
if: steps.changed-files.outputs.all
run: pip install -e .
- name: Build and test service A
- name: Build and test service ${{ matrix.example.name }}
if: steps.changed-files.outputs.all
working-directory: libs/cli/examples
working-directory: ${{ matrix.example.workdir }}
env:
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
run: |
# The build-arg isn't used; just testing that we accept other args
langgraph build -t langgraph-test-a --base-image "langchain/langgraph-trial"
cp .env.example .envg
timeout 60 python ../../../.github/scripts/run_langgraph_cli_test.py -c langgraph.json -t langgraph-test-a
- name: Build and test service B
if: steps.changed-files.outputs.all
working-directory: libs/cli/examples/graphs
run: |
langgraph build -t langgraph-test-b --base-image "langchain/langgraph-trial"
timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-b
- name: Build and test service C
if: steps.changed-files.outputs.all
working-directory: libs/cli/examples/graphs_reqs_a
run: |
langgraph build -t langgraph-test-c --base-image "langchain/langgraph-trial"
timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-c
- name: Build and test service D
if: steps.changed-files.outputs.all
working-directory: libs/cli/examples/graphs_reqs_b
run: |
langgraph build -t langgraph-test-d --base-image "langchain/langgraph-trial"
timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-d
# Build the image for this example
langgraph build -t ${{ matrix.example.tag }}
# Prepare environment file from local or parent example directory
if [ -f .env.example ]; then cp .env.example .env; elif [ -f ../.env.example ]; then cp ../.env.example .env && cp ../.env.example ../.env; fi
if [ -n "${{ secrets.LANGSMITH_API_KEY }}" ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env; if [ -f ../.env ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> ../.env; fi; fi
# Run the integration test using the built tag
# Compute repo root to reference the shared script robustly
REPO_ROOT=$(git rev-parse --show-toplevel)
timeout 60 python "$REPO_ROOT/.github/scripts/run_langgraph_cli_test.py" -t ${{ matrix.example.tag }}
- name: Build JS service
if: steps.changed-files.outputs.all
if: ${{ steps.changed-files.outputs.all && matrix.example.name == 'A' }}
working-directory: libs/cli/js-examples
run: |
langgraph build -t langgraph-test-e
- name: Build JS monorepo service
if: ${{ steps.changed-files.outputs.all && matrix.example.name == 'A' }}
working-directory: libs/cli/js-monorepo-example
run: |
langgraph build -t langgraph-test-f -c apps/agent/langgraph.json --build-command "yarn run turbo build" --install-command "yarn install"
- name: Build Python monorepo service
if: ${{ steps.changed-files.outputs.all && matrix.example.name == 'A' }}
working-directory: libs/cli/python-monorepo-example
run: |
langgraph build -t langgraph-test-g -c apps/agent/langgraph.json
cp apps/agent/.env.example apps/agent/.env
if [ -n "${{ secrets.LANGSMITH_API_KEY }}" ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> apps/agent/.env; fi
timeout 60 python ../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-g -c apps/agent/langgraph.json
- name: Build and test prerelease reqs service
if: ${{ steps.changed-files.outputs.all && matrix.example.name == 'A' }}
working-directory: libs/cli/examples/graph_prerelease_reqs
run: |
langgraph build -t langgraph-test-h
cp ../.env.example .env
if [ -n "${{ secrets.LANGSMITH_API_KEY }}" ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env; fi
timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-h
echo "Finished starting up langgraph-test-h"
LANGGRAPH_VERSION=$(docker run --rm --entrypoint "" langgraph-test-h python -c "import sys; from importlib.metadata import version; v = version('langgraph'); print(v);")
if [ "$LANGGRAPH_VERSION" != "1.0.2" ]; then
echo "LANGGRAPH_VERSION != 1.0.2; $LANGGRAPH_VERSION"
exit 1
fi
LANGCHAIN_OPENAI_VERSION=$(docker run --rm --entrypoint "" langgraph-test-h python -c "import sys; from importlib.metadata import version; v = version('langchain-openai'); print(v);")
if [ "$LANGCHAIN_OPENAI_VERSION" != "1.0.1" ]; then
echo "LANGCHAIN_OPENAI_VERSION != 1.0.1; $LANGCHAIN_OPENAI_VERSION"
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"
exit 1
fi
- name: Build and test prerelease reqs fail service
if: ${{ steps.changed-files.outputs.all && matrix.example.name == 'A' }}
working-directory: libs/cli/examples/graph_prerelease_reqs_fail
run: |
langgraph build -t langgraph-test-i || [ $? -eq 1 ]
+4 -4
View File
@@ -31,7 +31,7 @@ jobs:
- "3.12"
name: "lint #${{ matrix.python-version }}"
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Get changed files
id: changed-files
uses: Ana06/get-changed-files@v2.3.0
@@ -39,7 +39,7 @@ jobs:
filter: "${{ inputs.working-directory }}/**"
- name: Set up Python ${{ matrix.python-version }}
if: steps.changed-files.outputs.all
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ matrix.python-version }}
enable-cache: true
@@ -48,7 +48,7 @@ jobs:
- name: Install dependencies
if: steps.changed-files.outputs.all
working-directory: ${{ inputs.working-directory }}
run: uv sync --frozen --group dev
run: uv sync --frozen --group lint
- name: Get .mypy_cache to speed up mypy
if: steps.changed-files.outputs.all
@@ -74,7 +74,7 @@ jobs:
- name: Install test dependencies
if: steps.changed-files.outputs.all
working-directory: ${{ inputs.working-directory }}
run: uv sync --group dev
run: uv sync --group lint
- name: Get .mypy_cache_test to speed up mypy
if: steps.changed-files.outputs.all
+4 -4
View File
@@ -17,17 +17,17 @@ jobs:
strategy:
matrix:
python-version:
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3.13"
- "3.14"
name: "test #${{ matrix.python-version }}"
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ matrix.python-version }}
enable-cache: true
@@ -42,7 +42,7 @@ jobs:
- name: Install dependencies
shell: bash
working-directory: ${{ inputs.working-directory }}
run: uv sync --frozen --group dev
run: uv sync --frozen --group test --no-dev
- name: Run tests
shell: bash
+4 -4
View File
@@ -12,20 +12,20 @@ jobs:
strategy:
matrix:
python-version:
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3.13"
- "3.14"
defaults:
run:
working-directory: libs/langgraph
name: "test #${{ matrix.python-version }}"
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ matrix.python-version }}
enable-cache: true
@@ -39,7 +39,7 @@ jobs:
- name: Install dependencies
shell: bash
run: uv sync --frozen --group dev
run: uv sync --frozen --group test --no-dev
- name: Run tests
shell: bash
+5 -6
View File
@@ -16,7 +16,6 @@ permissions:
jobs:
build:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
outputs:
@@ -24,10 +23,10 @@ jobs:
version: ${{ steps.check-version.outputs.version }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up Python $${ env.PYTHON_VERSION }}
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ env.PYTHON_VERSION }}
enable-cache: true
@@ -49,7 +48,7 @@ jobs:
working-directory: ${{ inputs.working-directory }}
- name: Upload build
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: test-dist
path: ${{ inputs.working-directory }}/dist/
@@ -75,9 +74,9 @@ jobs:
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v6
with:
name: test-dist
path: ${{ inputs.working-directory }}/dist/
+3 -3
View File
@@ -17,16 +17,16 @@ jobs:
run:
working-directory: libs/langgraph
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- run: SHA=$(git rev-parse HEAD) && echo "SHA=$SHA" >> $GITHUB_ENV
- name: Set up Python 3.11
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@v7
with:
python-version: "3.11"
enable-cache: true
cache-suffix: "bench"
- name: Install dependencies
run: uv sync --group dev
run: uv sync --group test
- name: Run benchmarks
run: OUTPUT=out/benchmark-baseline.json make -s benchmark
- name: Save outputs
+4 -4
View File
@@ -15,20 +15,20 @@ jobs:
run:
working-directory: libs/langgraph
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- id: files
name: Get changed files
uses: Ana06/get-changed-files@v2.3.0
with:
format: json
- name: Set up Python 3.11
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@v7
with:
python-version: "3.11"
enable-cache: true
cache-suffix: "bench"
- name: Install dependencies
run: uv sync --group dev
run: uv sync --group test
- name: Download baseline
uses: actions/cache/restore@v4
with:
@@ -57,7 +57,7 @@ jobs:
echo EOF
} >> "$GITHUB_OUTPUT"
- name: Annotation
uses: actions/github-script@v7
uses: actions/github-script@v8
with:
script: |
const file = JSON.parse(`${{ steps.files.outputs.added_modified_renamed }}`)[0]
+8 -6
View File
@@ -3,7 +3,8 @@ name: CI
on:
push:
branches: [main, v1]
branches:
- main
pull_request:
permissions:
@@ -26,7 +27,7 @@ jobs:
python: ${{ steps.filter.outputs.python }}
deps: ${{ steps.filter.outputs.deps }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: dorny/paths-filter@v3
id: filter
with:
@@ -77,6 +78,7 @@ jobs:
"libs/checkpoint-sqlite",
"libs/checkpoint-postgres",
"libs/prebuilt",
"libs/sdk-py",
]
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.deps == 'true'
uses: ./.github/workflows/_test.yml
@@ -98,9 +100,9 @@ jobs:
name: "Check SDK methods matching"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Run check_sdk_methods script
@@ -116,9 +118,9 @@ jobs:
python-version:
- "3.11"
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@v7
with:
python-version: "3.11"
enable-cache: true
+1 -1
View File
@@ -21,7 +21,7 @@
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Install Dependencies
run: |
-150
View File
@@ -1,150 +0,0 @@
name: Deploy Docs
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
defaults:
run:
working-directory: docs
jobs:
get-changed-files:
runs-on: ubuntu-latest
outputs:
changed-files: ${{ steps.changed-files.outputs.added_modified }}
steps:
- uses: actions/checkout@v4
- name: Get changed files
id: changed-files
uses: Ana06/get-changed-files@v2.3.0
with:
filter: "docs/docs/**"
deploy:
runs-on: ubuntu-latest
timeout-minutes: 10 # Job will be cancelled if it runs for more than 10 minutes
env:
GITHUB_TOKEN: ${{ secrets.MKDOCS_GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python
uses: astral-sh/setup-uv@v6
with:
python-version: "3.12"
enable-cache: true
cache-suffix: "docs"
- name: Install dependencies
run: |
yarn
uv sync --all-groups
# we run this installation only for internal PRs
# as GITHUB_TOKEN is not available for PRs from outside contributors
if [ -n "${GITHUB_TOKEN}" ]; then
uv run pip install "git+https://${GITHUB_TOKEN}@github.com/langchain-ai/mkdocs-material-insiders.git"
fi
- name: Run unit tests
# Run unit tests on the docs build pipeline
run: make tests
- name: Lint Docs
# This step lints the docs using the existing linting set up.
# It should be very fast and should not require any external services.
run: make lint-docs
- name: Build llms-text
run: make llms-text
- name: Build site
run: |
# If this is main branch, then we want to download stats. we do this
# with the env variable DOWNLOAD_STATS=true
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
DOWNLOAD_STATS=true make build-docs
else
make build-docs
fi
env:
MKDOCS_GIT_COMMITTERS_APIKEY: ${{ secrets.MKDOCS_GIT_COMMITTERS_APIKEY }}
OPENAI_API_KEY: sf-proj-1234567890 # fake placeholder, shouldn't actually be used
ANTHROPIC_API_KEY: sk-ant-api03-1234567890 # fake placeholder, shouldn't actually be used
- name: Check links in notebooks
env:
LANGCHAIN_API_KEY: test
if: github.event_name == 'schedule'
run: |
if [ "${{ github.event_name }}" == "schedule" ]; then
echo "Running link check on all HTML files matching notebooks in docs directory..."
uv run pytest -v \
--check-links-ignore "https://(api|web|docs)\.smith\.langchain\.com/.*" \
--check-links-ignore "https://academy\.langchain\.com/.*" \
--check-links-ignore "https://x.com/.*" \
--check-links-ignore "https://twitter.com/.*" \
--check-links-ignore "https://github\.com/.*" \
--check-links-ignore "http://localhost:8123/.*" \
--check-links-ignore "http://localhost:2024.*" \
--check-links-ignore "http://127.0.0.1:.*" \
--check-links-ignore "/.*\.(ipynb|html)$" \
--check-links-ignore "https://python\.langchain\.com/.*" \
--check-links-ignore "https://openai\.com/.*" \
--check-links-ignore "https://www\.uber\.com/.*" \
--check-links-ignore "https://pepy\.tech/.*" \
--check-links-ignore "docs/docs/static/wordmark_*" \
--check-links $(find site -name "index.html" | grep -v 'storm/index.html')
else
echo "Fetching changes from origin/main..."
git fetch origin main
echo "Checking for changed notebook files..."
CHANGED_FILES=$(git diff --name-only --diff-filter=d origin/main | grep 'docs/docs/.*\.ipynb$' | grep -v 'storm.ipynb' | sed -E 's|^docs/docs/|site/|; s/\.ipynb$/\/index.html/' || true)
echo "Changed files: ${CHANGED_FILES}"
if [ -n "${CHANGED_FILES}" ]; then
echo "Running link check on HTML files matching changed notebook files..."
uv run pytest -v \
--check-links-ignore "https://(api|web|docs)\.smith\.langchain\.com/.*" \
--check-links-ignore "https://academy\.langchain\.com/.*" \
--check-links-ignore "http://localhost:8123/.*" \
--check-links-ignore "http://localhost:2024.*" \
--check-links-ignore "http://127.0.0.1:.*" \
--check-links-ignore "https://x.com/.*" \
--check-links-ignore "https://twitter.com/.*" \
--check-links-ignore "https://github\.com/.*" \
--check-links-ignore "/.*\.(ipynb|html)$" \
--check-links-ignore "docs/docs/static/wordmark_*" \
--check-links ${CHANGED_FILES} \
|| ([ $? = 5 ] && exit 0 || exit $?)
else
echo "No notebook files changed."
fi
fi
- name: Configure GitHub Pages
if: github.ref == 'refs/heads/main'
uses: actions/configure-pages@v5
- name: Upload Pages Artifact
# if: github.ref == 'refs/heads/main'
uses: actions/upload-pages-artifact@v3
with:
path: ./docs/site/
- name: Deploy to GitHub Pages
if: github.ref == 'refs/heads/main'
id: deployment
uses: actions/deploy-pages@v4
+2 -2
View File
@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0
@@ -36,7 +36,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 1
+2 -1
View File
@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Validate PR Title
uses: amannn/action-semantic-pull-request@v5
uses: amannn/action-semantic-pull-request@v6
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@@ -40,6 +40,7 @@ jobs:
sdk-py
docs
ci
deps
requireScope: false
ignoreLabels: |
ignore-lint-pr-title
+21 -15
View File
@@ -16,7 +16,6 @@ env:
jobs:
build:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
outputs:
@@ -26,10 +25,10 @@ jobs:
tag: ${{ steps.check-version.outputs.tag }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up Python
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ env.PYTHON_VERSION }}
enable-cache: true
@@ -51,7 +50,7 @@ jobs:
working-directory: ${{ inputs.working-directory }}
- name: Upload build
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: dist
path: ${{ inputs.working-directory }}/dist/
@@ -62,7 +61,13 @@ jobs:
working-directory: ${{ inputs.working-directory }}
run: |
PKG_NAME=$(grep -m 1 "^name = " pyproject.toml | cut -d '"' -f 2)
VERSION=$(grep -m 1 "^version = " pyproject.toml | cut -d '"' -f 2)
if grep -q 'dynamic.*=.*\[.*"version".*\]' pyproject.toml; then
# handle dynamic versioning
DIR_NAME=$(echo "$PKG_NAME" | tr '-' '_')
VERSION=$(grep -m 1 '^__version__' "${DIR_NAME}/__init__.py" | cut -d '"' -f 2)
else
VERSION=$(grep -m 1 "^version = " pyproject.toml | cut -d '"' -f 2)
fi
SHORT_PKG_NAME="$(echo "$PKG_NAME" | sed -e 's/langgraph//g' -e 's/-//g')"
if [ -z $SHORT_PKG_NAME ]; then
TAG="$VERSION"
@@ -81,7 +86,7 @@ jobs:
outputs:
release-body: ${{ steps.generate-release-body.outputs.release-body }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
repository: langchain-ai/langgraph
path: langgraph
@@ -152,7 +157,7 @@ jobs:
- test-pypi-publish
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
# We explicitly *don't* set up caching here. This ensures our tests are
# maximally sensitive to catching breakage.
@@ -168,7 +173,7 @@ jobs:
# used in the real world.
- name: Set up Python
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ env.PYTHON_VERSION }}
enable-cache: true
@@ -216,7 +221,7 @@ jobs:
uv run python -c "import $IMPORT_NAME; print(dir($IMPORT_NAME))"
- name: Import test dependencies
run: uv sync --group dev
run: uv sync --group test
working-directory: ${{ inputs.working-directory }}
# Overwrite the local version of the package with the test PyPI version.
@@ -255,16 +260,16 @@ jobs:
working-directory: ${{ inputs.working-directory }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up Python
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ env.PYTHON_VERSION }}
enable-cache: true
cache-suffix: "release"
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v6
with:
name: dist
path: ${{ inputs.working-directory }}/dist/
@@ -296,16 +301,16 @@ jobs:
working-directory: ${{ inputs.working-directory }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up Python
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@v7
with:
python-version: ${{ env.PYTHON_VERSION }}
enable-cache: true
cache-suffix: "release"
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v6
with:
name: dist
path: ${{ inputs.working-directory }}/dist/
@@ -317,5 +322,6 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
generateReleaseNotes: false
tag: ${{needs.build.outputs.tag}}
name: ${{ needs.build.outputs.pkg-name }}==${{ needs.build.outputs.version }}
body: ${{ needs.release-notes.outputs.release-body }}
commit: ${{ github.sha }}
+2 -2
View File
@@ -28,9 +28,9 @@ jobs:
- "latest"
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up Python + Poetry
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@v7
with:
python-version: "3.11"
enable-cache: true
+5 -5
View File
@@ -16,13 +16,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up uv
uses: astral-sh/setup-uv@v6
uses: astral-sh/setup-uv@v7
with:
# use minimum supported Python version
python-version: "3.9"
python-version: "3.10"
enable-cache: true
cache-suffix: "uv-lock-upgrade"
@@ -33,8 +33,8 @@ jobs:
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "chore[deps]: upgrade dependencies with `uv lock --upgrade`"
title: "chore[deps]: upgrade dependencies with `uv lock --upgrade`"
commit-message: "chore(deps): upgrade dependencies with `uv lock --upgrade`"
title: "chore(deps): upgrade dependencies with `uv lock --upgrade`"
body: |
This PR updates the dependencies in all Python packages using `uv lock --upgrade`.
+1 -1
View File
@@ -28,7 +28,7 @@ Below is a high-level overview:
- **langgraph** core framework for building stateful, multi-actor agents.
- **prebuilt** high-level APIs for creating and running agents and tools.
- **sdk-js** JS/TS SDK for interacting with the LangGraph REST API.
- **sdk-py** Python SDK for the LangGraph Platform API.
- **sdk-py** Python SDK for the LangGraph Server API.
### Dependency map
+3 -3
View File
@@ -277,9 +277,9 @@ def my_function(arg1: int, arg2: str) -> float:
Examples:
This is a section for examples of how to use the function.
.. code-block:: python
my_function(1, "hello")
```python
my_function(1, "hello")
\```
Args:
arg1: This is a description of arg1. We do not need to specify the type since
+5 -5
View File
@@ -63,15 +63,15 @@ LangGraph provides low-level supporting infrastructure for *any* long-running, s
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.
- [LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform/) — 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://langchain-ai.github.io/langgraph/concepts/langgraph_studio/).
- [LangChain](https://python.langchain.com/docs/introduction/) Provides integrations and composable components to streamline LLM application development.
- [LangSmith Deployment](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform/) — 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://langchain-ai.github.io/langgraph/concepts/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://langchain-ai.github.io/langgraphjs/).
> 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://langchain-ai.github.io/langgraph/how-tos/): Quick, actionable code snippets for topics such as streaming, adding memory & persistence, and design patterns (e.g. branching, subgraphs, etc.).
- [Guides](https://langchain-ai.github.io/langgraph/guides/): Quick, actionable code snippets for topics such as streaming, adding memory & persistence, and design patterns (e.g. branching, subgraphs, etc.).
- [Reference](https://langchain-ai.github.io/langgraph/reference/graphs/): Detailed reference on core classes, methods, how to use the graph and checkpointing APIs, and higher-level prebuilt components.
- [Examples](https://langchain-ai.github.io/langgraph/examples/): 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.
@@ -81,4 +81,4 @@ While LangGraph can be used standalone, it also integrates seamlessly with any L
## Acknowledgements
LangGraph is inspired by [Pregel](https://research.google/pubs/pub37252/) and [Apache Beam](https://beam.apache.org/). The public interface draws inspiration from [NetworkX](https://networkx.org/documentation/latest/). LangGraph is built by LangChain Inc, the creators of LangChain, but can be used without LangChain.
LangGraph is inspired by [Pregel](https://research.google/pubs/pub37252/) and [Apache Beam](https://beam.apache.org/). The public interface draws inspiration from [NetworkX](https://networkx.org/documentation/latest/). LangGraph is built by LangChain Inc, the creators of LangChain, but can be used without LangChain.
+3
View File
@@ -18,6 +18,9 @@ build-prebuilt:
build-docs: build-prebuilt
TARGET_LANGUAGE=python uv run python -m mkdocs build --clean -f mkdocs.yml --strict
build-docs-js: build-prebuilt
TARGET_LANGUAGE=js uv run python -m mkdocs build --clean -f mkdocs.yml --strict
llms-text:
uv run python -m _scripts.generate_llms_text docs/llms-full.txt
+113 -10
View File
@@ -1,24 +1,126 @@
# Setup
# LangGraph Documentation
To setup requirements for building docs you can run:
For more information on contributing to our documentation, see the [Contributing Guide](../CONTRIBUTING.md).
```bash
uv sync --group test
## Structure
The primary documentation is located in the `docs/` directory. This directory contains both the source files for the main documentation as well as the API reference doc build process.
### Main Documentation
Main documentation files are located in `docs/docs/` and are written in Markdown format. The site uses [**MkDocs**](https://www.mkdocs.org/) with the [Material theme](https://squidfunk.github.io/mkdocs-material/) and includes:
- **Concepts**: Core LangGraph concepts and explanations
- **Tutorials**: Step-by-step learning guides
- **How-tos**: Task-focused guides for specific use cases
- **Examples**: Real-world applications and use cases
- **Jupyter Notebooks**: Interactive tutorials that are automatically converted to markdown
### API Reference
API reference documentation is defined in `docs/docs/reference/`. Each `.md` file outlines the "template" that each page is built from. Reference content is automatically generated from docstrings in the codebase using the **mkdocstrings** plugin. Once generated, the content is plugged into the corresponding markdown file where it is referenced by using manual directives to specify which classes and/or functions are documented:
```markdown
::: langgraph.graph.state.StateGraph
options:
show_if_no_docstring: true
show_root_heading: true
show_root_full_path: false
members:
- add_node
- add_edge
- add_conditional_edges
- add_sequence
- compile
```
## Serving documentation locally
## Build Process
To run the documentation server locally you can run:
Docs are built following these steps:
1. **Content Processing:**
- `_scripts/notebook_hooks.py` - Main processing pipeline that:
- Converts how-tos/tutorial Jupyter notebooks to markdown using `notebook_convert.py`
- Adds automatic API reference links to code blocks using `generate_api_reference_links.py`
- Handles conditional rendering for Python/JS versions
- Processes highlight comments and custom syntax
2. **API Reference Generation:**
- **mkdocstrings** plugin extracts docstrings from Python source code
- Manual `::: module.Class` directives in reference pages (`/docs/docs/*`) specify what to document
- Cross-references are automatically generated between docs and API
3. **Site Generation:**
- **MkDocs** processes all markdown files and generates static HTML
- Custom hooks handle redirects and inject additional functionality
4. **Deployment:**
- Site is deployed with Vercel
- `make build-docs` generates production build (also usable for local testing)
- Automatic redirects handle URL changes between versions
### Local Development
For local development, use the Makefile targets:
```bash
# Serve docs locally with hot reloading
make serve-docs
# Clean build for production testing
make build-docs
# Serve with clean build
make serve-clean-docs
```
This will start the documentation server on [http://127.0.0.1:8000/langgraph/](http://127.0.0.1:8000/langgraph/).
The `serve-docs` command:
- Watches source files for changes
- Includes dirty builds for faster iteration
- Serves on [http://127.0.0.1:8000/langgraph/](http://127.0.0.1:8000/langgraph/)
## Standards
**Docstring Format:**
The API reference uses **Google-style docstrings** with Markdown markup. The `mkdocstrings` plugin processes these to generate documentation.
**Required format:**
```python
def example_function(param1: str, param2: int = 5) -> bool:
"""Brief description of the function.
Longer description can go here. Use Markdown syntax for
rich formatting like **bold** and *italic*.
Args:
param1: Description of the first parameter.
param2: Description of the second parameter with default value.
Returns:
Description of the return value.
Raises:
ValueError: When param1 is empty.
TypeError: When param2 is not an integer.
!!! warning
This function is experimental and may change.
!!! version-added "Added in version 0.2.0"
"""
```
**Special Markers:**
- **MkDocs admonitions**: `!!! warning`, `!!! note`, `!!! version-added`
- **Code blocks**: Standard markdown ``` syntax
- **Cross-references**: Automatic linking via `generate_api_reference_links.py`
## Execute notebooks
If you would like to automatically execute all of the notebooks, to mimic the "Run notebooks" GHA, you can run:
If you would like to automatically execute all of the notebooks, to mimic the "Run notebooks" GitHub action, you can run:
```bash
python _scripts/prepare_notebooks_for_ci.py
@@ -33,8 +135,9 @@ python _scripts/prepare_notebooks_for_ci.py --comment-install-cells
```
`prepare_notebooks_for_ci.py` script will add VCR cassette context manager for each cell in the notebook, so that:
* when the notebook is run for the first time, cells with network requests will be recorded to a VCR cassette file
* when the notebook is run subsequently, the cells with network requests will be replayed from the cassettes
- when the notebook is run for the first time, cells with network requests will be recorded to a VCR cassette file
- when the notebook is run subsequently, the cells with network requests will be replayed from the cassettes
## Adding new notebooks
+14 -2
View File
@@ -1,3 +1,5 @@
"""Generate API reference links for imports in Python code blocks within markdown files."""
import ast
import importlib
import logging
@@ -70,8 +72,18 @@ MANUAL_API_REFERENCES_LANGGRAPH = [
([], "langgraph.checkpoint.postgres.aio", "AsyncPostgresSaver", "checkpoints"),
([], "langgraph.checkpoint.postgres", "PostgresSaver", "checkpoints"),
# other prebuilts
(["langgraph_supervisor"], "langgraph_supervisor.supervisor", "create_supervisor", "supervisor"),
(["langgraph_supervisor"], "langgraph_supervisor.handoff", "create_handoff_tool", "supervisor"),
(
["langgraph_supervisor"],
"langgraph_supervisor.supervisor",
"create_supervisor",
"supervisor",
),
(
["langgraph_supervisor"],
"langgraph_supervisor.handoff",
"create_handoff_tool",
"supervisor",
),
([], "langgraph_supervisor.handoff", "create_forward_message_tool", "supervisor"),
(["langgraph_swarm"], "langgraph_swarm.swarm", "create_swarm", "swarm"),
(["langgraph_swarm"], "langgraph_swarm.swarm", "add_active_agent_router", "swarm"),
+10 -4
View File
@@ -29,7 +29,11 @@ logger = logging.getLogger(__name__)
def _transform_link(
link_name: str, scope: str, file_path: str, line_number: int, custom_title: Optional[str] = None
link_name: str,
scope: str,
file_path: str,
line_number: int,
custom_title: Optional[str] = None,
) -> Optional[str]:
"""Transform a cross-reference link based on the current scope.
@@ -38,7 +42,7 @@ def _transform_link(
scope: The current scope context ("global", "python", "js", etc.).
file_path: The file path for error reporting.
line_number: The line number for error reporting.
custom_title: Optional custom title for the link. If None, uses link_name.
custom_title: Optional custom title for the link. If `None`, uses link_name.
Returns:
A formatted markdown link if the link is found in the scope mapping,
@@ -117,7 +121,9 @@ CROSS_REFERENCE_PATTERN = re.compile(
)
def _replace_autolinks(markdown: str, file_path: str, *, default_scope: str = "python") -> str:
def _replace_autolinks(
markdown: str, file_path: str, *, default_scope: str = "python"
) -> str:
"""Preprocess markdown lines to handle @[links] with conditional fence scopes.
This function processes markdown content to transform @[link_name] references
@@ -169,7 +175,7 @@ def _replace_autolinks(markdown: str, file_path: str, *, default_scope: str = "p
# This is @[ref] format
link_name = match.group("link_name")
custom_title = None
transformed = _transform_link(
link_name, current_scope, file_path, line_number, custom_title
)
@@ -2108,9 +2108,9 @@ __metadata:
linkType: hard
"hono@npm:^4.5.4":
version: 4.8.9
resolution: "hono@npm:4.8.9"
checksum: 10c0/385539d1787fdc747bc869ef0e5ccc9f39cbe40289b94f23eecfc82c6ca440f059704647cd6381a5066d2cf7baa43ab25184c78d44af4c5c98a5c5b07670059e
version: 4.10.3
resolution: "hono@npm:4.10.3"
checksum: 10c0/bdcc4c7066c74ba7cfa63ed6550768a0f43a420286c8f8f74b7012ea4901b8b06778fa8e98264b46f1a86920f056b7ede1f07814da4934912f9945def4977c29
languageName: node
linkType: hard
@@ -2340,13 +2340,13 @@ __metadata:
linkType: hard
"js-yaml@npm:^4.1.0":
version: 4.1.0
resolution: "js-yaml@npm:4.1.0"
version: 4.1.1
resolution: "js-yaml@npm:4.1.1"
dependencies:
argparse: "npm:^2.0.1"
bin:
js-yaml: bin/js-yaml.js
checksum: 10c0/184a24b4eaacfce40ad9074c64fd42ac83cf74d8c8cd137718d456ced75051229e5061b8633c3366b8aada17945a7a356b337828c19da92b51ae62126575018f
checksum: 10c0/561c7d7088c40a9bb53cc75becbfb1df6ae49b34b5e6e5a81744b14ae8667ec564ad2527709d1a6e7d5e5fa6d483aa0f373a50ad98d42fde368ec4a190d4fae7
languageName: node
linkType: hard
+50 -66
View File
@@ -4,52 +4,48 @@ This module provides link mappings for different language/framework scopes
to resolve @[link_name] references to actual URLs.
"""
# Python-specific link mappings
# Python-specific link mappings
PYTHON_LINK_MAP = {
"StateGraph": "reference/graphs/#langgraph.graph.StateGraph",
"add_conditional_edges": "reference/graphs/#langgraph.graph.StateGraph.add_conditional_edges",
"add_edge": "reference/graphs/#langgraph.graph.StateGraph.add_edge",
"add_node": "reference/graphs/#langgraph.graph.StateGraph.add_node",
"add_messages": "reference/messages/#langgraph.graph.message.add_messages",
"ToolNode": "reference/prebuilt/#langgraph.prebuilt.tool_node.ToolNode",
"add_conditional_edges": "reference/graphs/#langgraph.graph.state.StateGraph.add_conditional_edges",
"add_edge": "reference/graphs/#langgraph.graph.state.StateGraph.add_edge",
"add_node": "reference/graphs/#langgraph.graph.state.StateGraph.add_node",
"add_messages": "reference/graphs/#langgraph.graph.message.add_messages",
"ToolNode": "reference/agents/#langgraph.prebuilt.tool_node.ToolNode",
"CompiledStateGraph.astream": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.astream",
"Pregel.astream": "reference/graphs/#langgraph.pregel.Pregel.astream",
"Pregel.astream": "reference/pregel/#langgraph.pregel.Pregel.astream",
"AsyncPostgresSaver": "reference/checkpoints/#langgraph.checkpoint.postgres.aio.AsyncPostgresSaver",
"AsyncSqliteSaver": "reference/checkpoints/#langgraph.checkpoint.sqlite.aio.AsyncSqliteSaver",
"BaseCheckpointSaver": "reference/checkpoints/#langgraph.checkpoint.base.BaseCheckpointSaver",
"BaseStore": "reference/stores/#langgraph.store.base.BaseStore",
"BaseStore.put": "reference/stores/#langgraph.store.base.BaseStore.put",
"BinaryOperatorAggregate": "reference/channels/#langgraph.channels.BinaryOperatorAggregate",
"BaseStore": "reference/store/#langgraph.store.base.BaseStore",
"BaseStore.put": "reference/store/#langgraph.store.base.BaseStore.put",
"BinaryOperatorAggregate": "reference/pregel/#langgraph.pregel.Pregel--advanced-channels-context-and-binaryoperatoraggregate",
"CipherProtocol": "reference/checkpoints/#langgraph.checkpoint.serde.base.CipherProtocol",
"client.runs.stream": "reference/client/#langgraph_sdk.client.RunsClient.stream",
"client.runs.wait": "reference/client/#langgraph_sdk.client.RunsClient.wait",
"client.threads.get_history": "reference/client/#langgraph_sdk.client.ThreadsClient.get_history",
"client.threads.update_state": "reference/client/#langgraph_sdk.client.ThreadsClient.update_state",
"client.runs.stream": "cloud/reference/sdk/python_sdk_ref/#langgraph_sdk.client.RunsClient.stream",
"client.runs.wait": "cloud/reference/sdk/python_sdk_ref/#langgraph_sdk.client.RunsClient.wait",
"client.threads.get_history": "cloud/reference/sdk/python_sdk_ref/#langgraph_sdk.client.ThreadsClient.get_history",
"client.threads.update_state": "cloud/reference/sdk/python_sdk_ref/#langgraph_sdk.client.ThreadsClient.update_state",
"Command": "reference/types/#langgraph.types.Command",
"CompiledStateGraph": "reference/graphs/#langgraph.graph.state.CompiledStateGraph",
"create_react_agent": "reference/prebuilt/#langgraph.prebuilt.chat_agent_executor.create_react_agent",
"create_supervisor": "reference/supervisor/#langgraph_supervisor.supervisor.create_supervisor",
"EncryptedSerializer": "reference/checkpoints/#langgraph.checkpoint.serde.encrypted.EncryptedSerializer",
"entrypoint.final": "reference/functions/#langgraph.func.entrypoint.final",
"entrypoint": "reference/functions/#langgraph.func.entrypoint",
"entrypoint.final": "reference/func/#langgraph.func.entrypoint.final",
"entrypoint": "reference/func/#langgraph.func.entrypoint",
"from_pycryptodome_aes": "reference/checkpoints/#langgraph.checkpoint.serde.encrypted.EncryptedSerializer.from_pycryptodome_aes",
# "getContextVariable": "<insert-ref>",
"get_state_history": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.get_state_history",
"get_stream_writer": "reference/config/#langgraph.config.get_stream_writer",
"HumanInterrupt": "reference/prebuilt/#langgraph.prebuilt.interrupt.HumanInterrupt",
"InjectedState": "reference/prebuilt/#langgraph.prebuilt.InjectedState",
"InjectedState": "reference/agents/#langgraph.prebuilt.tool_node.InjectedState",
"InMemorySaver": "reference/checkpoints/#langgraph.checkpoint.memory.InMemorySaver",
"interrupt": "reference/graphs/#langgraph.graph.interrupt",
"interrupt": "reference/types/#langgraph.types.Interrupt",
"CompiledStateGraph.invoke": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.invoke",
"JsonPlusSerializer": "reference/checkpoints/#langgraph.checkpoint.serde.jsonplus.JsonPlusSerializer",
"langgraph.json": "reference/configuration/#configuration-file",
"langgraph.json": "cloud/reference/cli/#configuration-file",
"LastValue": "reference/channels/#langgraph.channels.LastValue",
# "MemorySaver": "<insert-ref>",
# "messagesStateReducer": "<insert-ref>",
"PostgresSaver": "reference/checkpoints/#langgraph.checkpoint.postgres.PostgresSaver",
"Pregel": "reference/graphs/#langgraph.pregel.Pregel",
"Pregel.stream": "reference/graphs/#langgraph.pregel.Pregel.stream",
"Pregel": "reference/pregel/",
"Pregel.stream": "reference/pregel/#langgraph.pregel.Pregel.stream",
"pre_model_hook": "reference/prebuilt/#langgraph.prebuilt.chat_agent_executor.create_react_agent",
"protocol": "reference/checkpoints/#langgraph.checkpoint.serde.base.SerializerProtocol",
"Send": "reference/types/#langgraph.types.Send",
@@ -57,68 +53,56 @@ PYTHON_LINK_MAP = {
"SqliteSaver": "reference/checkpoints/#langgraph.checkpoint.sqlite.SqliteSaver",
"START": "reference/constants/#langgraph.constants.START",
"CompiledStateGraph.stream": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.stream",
"task": "reference/functions/#langgraph.func.task",
"task": "reference/func/#langgraph.func.task",
"Topic": "reference/channels/#langgraph.channels.Topic",
"update_state": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.update_state",
}
# JavaScript-specific link mappings
JS_LINK_MAP = {
"Auth": "reference/classes/sdk_auth.Auth.html",
"StateGraph": "reference/classes/langgraph.StateGraph.html",
"add_conditional_edges": "reference/functions/langgraph_StateGraph.addConditionalEdges.html",
"add_edge": "reference/functions/langgraph_StateGraph.addEdge.html",
"add_node": "reference/functions/langgraph_StateGraph.addNode.html",
"add_messages": "reference/functions/langgraph_message.addMessages.html",
"add_conditional_edges": "/reference/classes/langgraph.StateGraph.html#addConditionalEdges",
"add_edge": "reference/classes/langgraph.StateGraph.html#addEdge",
"add_node": "reference/classes/langgraph.StateGraph.html#addNode",
"add_messages": "reference/modules/langgraph.html#addMessages",
"ToolNode": "reference/classes/langgraph_prebuilt.ToolNode.html",
"CompiledStateGraph.astream()": "reference/functions/langgraph_CompiledStateGraph.astream.html",
"Pregel.astream": "reference/functions/langgraph_Pregel.astream.html",
"AsyncPostgresSaver": "reference/classes/langgraph_checkpoint_postgres_aio.AsyncPostgresSaver.html",
"AsyncSqliteSaver": "reference/classes/langgraph_checkpoint_sqlite_aio.AsyncSqliteSaver.html",
"BaseCheckpointSaver": "reference/classes/langgraph_checkpoint_base.BaseCheckpointSaver.html",
"BaseStore": "reference/classes/langgraph_store_base.BaseStore.html",
"BaseStore.put": "reference/functions/langgraph_store_base.BaseStore.put.html",
"BinaryOperatorAggregate": "reference/classes/langgraph_channels.BinaryOperatorAggregate.html",
"CipherProtocol": "reference/classes/langgraph_checkpoint_serde_base.CipherProtocol.html",
"client.runs.stream": "reference/functions/langgraph_sdk_client.RunsClient.stream.html",
"client.runs.wait": "reference/functions/langgraph_sdk_client.RunsClient.wait.html",
"client.threads.get_history": "reference/functions/langgraph_sdk_client.ThreadsClient.getHistory.html",
"client.threads.update_state": "reference/functions/langgraph_sdk_client.ThreadsClient.updateState.html",
"BaseCheckpointSaver": "reference/classes/checkpoint.BaseCheckpointSaver.html",
"BaseStore": "reference/classes/checkpoint.BaseStore.html",
"BaseStore.put": "reference/classes/checkpoint.BaseStore.html#put",
"BinaryOperatorAggregate": "reference/classes/langgraph.BinaryOperatorAggregate.html",
"client.runs.stream": "reference/classes/sdk_client.RunsClient.html#stream",
"client.runs.wait": "reference/classes/sdk_client.RunsClient.html#wait",
"client.threads.get_history": "reference/classes/sdk_client.ThreadsClient.html#getHistory",
"client.threads.update_state": "reference/classes/sdk_client.ThreadsClient.html#updateState",
"Command": "reference/classes/langgraph.Command.html",
"CompiledStateGraph": "reference/classes/langgraph.CompiledStateGraph.html",
"create_react_agent": "reference/functions/langgraph_prebuilt.createReactAgent.html",
"create_supervisor": "reference/functions/langgraph_supervisor.createSupervisor.html",
"EncryptedSerializer": "reference/classes/langgraph_checkpoint_serde_encrypted.EncryptedSerializer.html",
"entrypoint.final": "reference/functions/langgraph_func.entrypoint.final.html",
"entrypoint": "reference/functions/langgraph_func.entrypoint.html",
"from_pycryptodome_aes": "reference/functions/langgraph_checkpoint_serde_encrypted.EncryptedSerializer.fromPycryptodomeAes.html",
"entrypoint.final": "reference/functions/langgraph.entrypoint.html#final",
"entrypoint": "reference/functions/langgraph.entrypoint.html",
"getContextVariable": "https://v03.api.js.langchain.com/functions/_langchain_core.context.getContextVariable.html",
"get_state_history": "reference/functions/langgraph_CompiledStateGraph.getStateHistory.html",
"get_stream_writer": "reference/functions/langgraph_config.getStreamWriter.html",
"HumanInterrupt": "reference/classes/langgraph_prebuilt.HumanInterrupt.html",
"InjectedState": "reference/classes/langgraph_prebuilt.InjectedState.html",
"InMemorySaver": "reference/classes/langgraph_checkpoint_memory.InMemorySaver.html",
"get_state_history": "reference/classes/langgraph.CompiledStateGraph.html#getStateHistory",
"HumanInterrupt": "reference/interfaces/langgraph_prebuilt.HumanInterrupt.html",
"interrupt": "reference/functions/langgraph.interrupt-2.html",
"CompiledStateGraph.invoke": "reference/functions/langgraph_CompiledStateGraph.invoke.html",
"JsonPlusSerializer": "reference/classes/langgraph_checkpoint_serde_jsonplus.JsonPlusSerializer.html",
"langgraph.json": "reference/configuration.html",
"LastValue": "reference/classes/langgraph_channels.LastValue.html",
"CompiledStateGraph.invoke": "reference/classes/langgraph.CompiledStateGraph.html#invoke",
"langgraph.json": "cloud/reference/cli/#configuration-file",
"MemorySaver": "reference/classes/checkpoint.MemorySaver.html",
"messagesStateReducer": "reference/functions/langgraph.messagesStateReducer.html",
"PostgresSaver": "reference/classes/langgraph_checkpoint_postgres.PostgresSaver.html",
"PostgresSaver": "reference/classes/checkpoint_postgres.PostgresSaver.html",
"Pregel": "reference/classes/langgraph.Pregel.html",
"Pregel.stream": "reference/functions/langgraph_Pregel.stream.html",
"Pregel.stream": "reference/classes/langgraph.Pregel.html#stream",
"pre_model_hook": "reference/functions/langgraph_prebuilt.createReactAgent.html",
"protocol": "reference/classes/langgraph_checkpoint_serde_base.SerializerProtocol.html",
"protocol": "reference/interfaces/checkpoint.SerializerProtocol.html",
"Send": "reference/classes/langgraph.Send.html",
"SerializerProtocol": "reference/classes/langgraph_checkpoint_serde_base.SerializerProtocol.html",
"SqliteSaver": "reference/classes/langgraph_checkpoint_sqlite.SqliteSaver.html",
"START": "reference/constants.html#START",
"CompiledStateGraph.stream": "reference/functions/langgraph_CompiledStateGraph.stream.html",
"task": "reference/functions/langgraph_func.task.html",
"Topic": "reference/classes/langgraph_channels.Topic.html",
"update_state": "reference/functions/langgraph_CompiledStateGraph.updateState.html",
"SerializerProtocol": "reference/interfaces/checkpoint.SerializerProtocol.html",
"SqliteSaver": "reference/classes/checkpoint_sqlite.SqliteSaver.html",
"START": "reference/variables/langgraph.START.html",
"CompiledStateGraph.stream": "reference/classes/langgraph.CompiledStateGraph.html#stream",
"task": "reference/functions/langgraph.task.html",
## TODO (hntrl): export Topic from langgraphjs
# "Topic": "reference/classes/langgraph_channels.Topic.html",
"update_state": "reference/classes/langgraph.CompiledStateGraph.html#updateState",
}
# TODO: Allow updating these to localhost for local development
+2
View File
@@ -1,3 +1,5 @@
"""Convert Jupyter notebooks to markdown with custom processing."""
import ast
import os
import re
+537 -123
View File
@@ -27,130 +27,430 @@ DISABLED = os.getenv("DISABLE_NOTEBOOK_CONVERT") in ("1", "true", "True")
REDIRECT_MAP = {
# lib redirects
"how-tos/stream-values.ipynb": "how-tos/streaming.md#stream-graph-state",
"how-tos/stream-updates.ipynb": "how-tos/streaming.md#stream-graph-state",
"how-tos/streaming-content.ipynb": "how-tos/streaming.md",
"how-tos/stream-multiple.ipynb": "how-tos/streaming.md#stream-multiple-nodes",
"how-tos/streaming-tokens-without-langchain.ipynb": "how-tos/streaming.md#use-with-any-llm",
"how-tos/streaming-from-final-node.ipynb": "how-tos/streaming-specific-nodes.ipynb",
"how-tos/streaming-events-from-within-tools-without-langchain.ipynb": "how-tos/streaming-events-from-within-tools.ipynb#example-without-langchain",
"how-tos/stream-values.ipynb": "https://docs.langchain.com/oss/python/langgraph/streaming",
"how-tos/stream-updates.ipynb": "https://docs.langchain.com/oss/python/langgraph/streaming",
"how-tos/streaming-content.ipynb": "https://docs.langchain.com/oss/python/langgraph/streaming",
"how-tos/stream-multiple.ipynb": "https://docs.langchain.com/oss/python/langgraph/streaming",
"how-tos/streaming-tokens-without-langchain.ipynb": "https://docs.langchain.com/oss/python/langgraph/streaming",
"how-tos/streaming-from-final-node.ipynb": "https://docs.langchain.com/oss/python/langgraph/streaming",
"how-tos/streaming-events-from-within-tools-without-langchain.ipynb": "https://docs.langchain.com/oss/python/langgraph/streaming",
# graph-api
"how-tos/state-reducers.ipynb": "how-tos/graph-api.md#define-and-update-state",
"how-tos/sequence.ipynb": "how-tos/graph-api.md#create-a-sequence-of-steps",
"how-tos/branching.ipynb": "how-tos/graph-api.md#create-branches",
"how-tos/recursion-limit.ipynb": "how-tos/graph-api.md#create-and-control-loops",
"how-tos/visualization.ipynb": "how-tos/graph-api.md#visualize-your-graph",
"how-tos/input_output_schema.ipynb": "how-tos/graph-api.md#define-input-and-output-schemas",
"how-tos/pass_private_state.ipynb": "how-tos/graph-api.md#pass-private-state-between-nodes",
"how-tos/state-model.ipynb": "how-tos/graph-api.md#use-pydantic-models-for-graph-state",
"how-tos/map-reduce.ipynb": "how-tos/graph-api.md#map-reduce-and-the-send-api",
"how-tos/command.ipynb": "how-tos/graph-api.md#combine-control-flow-and-state-updates-with-command",
"how-tos/configuration.ipynb": "how-tos/graph-api.md#add-runtime-configuration",
"how-tos/node-retries.ipynb": "how-tos/graph-api.md#add-retry-policies",
"how-tos/return-when-recursion-limit-hits.ipynb": "how-tos/graph-api.md#impose-a-recursion-limit",
"how-tos/async.ipynb": "how-tos/graph-api.md#async",
"how-tos/state-reducers.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#define-and-update-state",
"how-tos/sequence.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#create-a-sequence-of-steps",
"how-tos/branching.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#create-branches",
"how-tos/recursion-limit.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#create-and-control-loops",
"how-tos/visualization.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#visualize-your-graph",
"how-tos/input_output_schema.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#define-input-and-output-schemas",
"how-tos/pass_private_state.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#pass-private-state-between-nodes",
"how-tos/state-model.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#use-pydantic-models-for-graph-state",
"how-tos/map-reduce.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#map-reduce-and-the-send-api",
"how-tos/command.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#combine-control-flow-and-state-updates-with-command",
"how-tos/configuration.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#add-runtime-configuration",
"how-tos/node-retries.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#add-retry-policies",
"how-tos/return-when-recursion-limit-hits.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#impose-a-recursion-limit",
"how-tos/async.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api#async",
# memory how-tos
"how-tos/memory/manage-conversation-history.ipynb": "how-tos/memory/add-memory.md",
"how-tos/memory/delete-messages.ipynb": "how-tos/memory/add-memory.md#delete-messages",
"how-tos/memory/add-summary-conversation-history.ipynb": "how-tos/memory/add-memory.md#summarize-messages",
"how-tos/memory.ipynb": "how-tos/memory/add-memory.md",
"agents/memory.ipynb": "how-tos/memory/add-memory.md",
"how-tos/memory/manage-conversation-history.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory",
"how-tos/memory/delete-messages.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#delete-messages",
"how-tos/memory/add-summary-conversation-history.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#summarize-messages",
"how-tos/memory.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory",
"agents/memory.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory",
# subgraph how-tos
"how-tos/subgraph-transform-state.ipynb": "how-tos/subgraph.md#different-state-schemas",
"how-tos/subgraphs-manage-state.ipynb": "how-tos/subgraph.md#add-persistence",
"how-tos/subgraph-transform-state.ipynb": "https://docs.langchain.com/oss/python/langgraph/use-subgraphs#different-state-schemas",
"how-tos/subgraphs-manage-state.ipynb": "https://docs.langchain.com/oss/python/langgraph/use-subgraphs#add-persistence",
# persistence how-tos
"how-tos/persistence_postgres.ipynb": "how-tos/memory/add-memory.md#use-in-production",
"how-tos/persistence_mongodb.ipynb": "how-tos/memory/add-memory.md#use-in-production",
"how-tos/persistence_redis.ipynb": "how-tos/memory/add-memory.md#use-in-production",
"how-tos/subgraph-persistence.ipynb": "how-tos/memory/add-memory.md#use-with-subgraphs",
"how-tos/cross-thread-persistence.ipynb": "how-tos/memory/add-memory.md#add-long-term-memory",
"cloud/how-tos/copy_threads": "cloud/how-tos/use_threads",
"cloud/how-tos/check-thread-status": "cloud/how-tos/use_threads",
"cloud/concepts/threads.md": "concepts/persistence.md#threads",
"how-tos/persistence.ipynb": "how-tos/memory/add-memory.md",
"how-tos/persistence_postgres.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#use-in-production",
"how-tos/persistence_mongodb.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#use-in-production",
"how-tos/persistence_redis.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#use-in-production",
"how-tos/subgraph-persistence.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#use-with-subgraphs",
"how-tos/cross-thread-persistence.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory#add-long-term-memory",
"cloud/how-tos/copy_threads": "https://docs.langchain.com/langsmith/use-threads",
"cloud/how-tos/check-thread-status": "https://docs.langchain.com/langsmith/use-threads",
"cloud/concepts/threads.md": "https://docs.langchain.com/oss/python/langgraph/persistence#threads",
"how-tos/persistence.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory",
# tool calling how-tos
"how-tos/tool-calling-errors.ipynb": "how-tos/tool-calling.ipynb#handle-errors",
"how-tos/pass-config-to-tools.ipynb": "how-tos/tool-calling.ipynb#access-config",
"how-tos/pass-run-time-values-to-tools.ipynb": "how-tos/tool-calling.ipynb#read-state",
"how-tos/update-state-from-tools.ipynb": "how-tos/tool-calling.ipynb#update-state",
"agents/tools.md": "how-tos/tool-calling.md",
"how-tos/tool-calling-errors.ipynb": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
"how-tos/pass-config-to-tools.ipynb": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
"how-tos/pass-run-time-values-to-tools.ipynb": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
"how-tos/update-state-from-tools.ipynb": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
"agents/tools.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
# multi-agent how-tos
"how-tos/agent-handoffs.ipynb": "how-tos/multi_agent.md#handoffs",
"how-tos/multi-agent-network.ipynb": "how-tos/multi_agent.md#use-in-a-multi-agent-system",
"how-tos/multi-agent-multi-turn-convo.ipynb": "how-tos/multi_agent.md#multi-turn-conversation",
"how-tos/agent-handoffs.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api",
"how-tos/multi-agent-network.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api",
"how-tos/multi-agent-multi-turn-convo.ipynb": "https://docs.langchain.com/oss/python/langgraph/graph-api",
# cloud redirects
"cloud/index.md": "index.md",
"cloud/how-tos/index.md": "concepts/langgraph_platform",
"cloud/concepts/api.md": "concepts/langgraph_server.md",
"cloud/concepts/cloud.md": "concepts/langgraph_cloud.md",
"cloud/faq/studio.md": "concepts/langgraph_studio.md#studio-faqs",
"cloud/how-tos/human_in_the_loop_edit_state.md": "cloud/how-tos/add-human-in-the-loop.md",
"cloud/how-tos/human_in_the_loop_user_input.md": "cloud/how-tos/add-human-in-the-loop.md",
"concepts/platform_architecture.md": "concepts/langgraph_cloud#architecture",
"cloud/index.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"cloud/how-tos/index.md": "https://docs.langchain.com/langsmith/home",
"cloud/concepts/api.md": "https://docs.langchain.com/langsmith/agent-server",
"cloud/concepts/cloud.md": "https://docs.langchain.com/langsmith/cloud",
"cloud/faq/studio.md": "https://docs.langchain.com/langsmith/studio",
"cloud/how-tos/human_in_the_loop_edit_state.md": "https://docs.langchain.com/langsmith/add-human-in-the-loop",
"cloud/how-tos/human_in_the_loop_user_input.md": "https://docs.langchain.com/langsmith/add-human-in-the-loop",
"concepts/platform_architecture.md": "https://docs.langchain.com/langsmith/cloud#architecture",
# cloud streaming redirects
"cloud/how-tos/stream_values.md": "cloud/how-tos/streaming.md#stream-graph-state",
"cloud/how-tos/stream_updates.md": "cloud/how-tos/streaming.md#stream-graph-state",
"cloud/how-tos/stream_messages.md": "cloud/how-tos/streaming.md#messages",
"cloud/how-tos/stream_events.md": "cloud/how-tos/streaming.md#stream-events",
"cloud/how-tos/stream_debug.md": "cloud/how-tos/streaming.md#debug",
"cloud/how-tos/stream_multiple.md": "cloud/how-tos/streaming.md#stream-multiple-modes",
"cloud/concepts/streaming.md": "concepts/streaming.md",
"agents/streaming.md": "how-tos/streaming.md",
"cloud/how-tos/stream_values.md": "https://docs.langchain.com/langsmith/streaming",
"cloud/how-tos/stream_updates.md": "https://docs.langchain.com/langsmith/streaming",
"cloud/how-tos/stream_messages.md": "https://docs.langchain.com/langsmith/streaming",
"cloud/how-tos/stream_events.md": "https://docs.langchain.com/langsmith/streaming",
"cloud/how-tos/stream_debug.md": "https://docs.langchain.com/langsmith/streaming",
"cloud/how-tos/stream_multiple.md": "https://docs.langchain.com/langsmith/streaming",
"cloud/concepts/streaming.md": "https://docs.langchain.com/oss/python/langgraph/streaming",
"agents/streaming.md": "https://docs.langchain.com/oss/python/langgraph/streaming",
# prebuilt redirects
"how-tos/create-react-agent.ipynb": "agents/agents.md#basic-configuration",
"how-tos/create-react-agent-memory.ipynb": "agents/memory.md",
"how-tos/create-react-agent-system-prompt.ipynb": "agents/context.md#prompts",
"how-tos/create-react-agent-structured-output.ipynb": "agents/agents.md#structured-output",
"how-tos/create-react-agent.ipynb": "https://docs.langchain.com/oss/python/langchain/agents#basic-configuration",
"how-tos/create-react-agent-memory.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory",
"how-tos/create-react-agent-system-prompt.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory",
"how-tos/create-react-agent-structured-output.ipynb": "https://docs.langchain.com/oss/python/langchain/agents#structured-output",
# misc
"prebuilt.md": "agents/prebuilt.md",
"reference/prebuilt.md": "reference/agents.md",
"concepts/high_level.md": "index.md",
"concepts/index.md": "index.md",
"concepts/v0-human-in-the-loop.md": "concepts/human-in-the-loop.md",
"how-tos/index.md": "index.md",
"tutorials/introduction.ipynb": "concepts/why-langgraph.md",
"agents/deployment.md": "tutorials/langgraph-platform/local-server.md",
"prebuilt.md": "https://docs.langchain.com/oss/python/langchain/agents",
"reference/prebuilt.md": "https://reference.langchain.com/python/langgraph/agents/",
"concepts/high_level.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"concepts/index.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"concepts/v0-human-in-the-loop.md": "https://docs.langchain.com/oss/python/langgraph/interrupts",
"how-tos/index.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"tutorials/introduction.ipynb": "https://docs.langchain.com/oss/python/langgraph/overview",
"agents/deployment.md": "https://docs.langchain.com/oss/python/langgraph/local-server",
# deployment redirects
"how-tos/deploy-self-hosted.md": "cloud/deployment/self_hosted_data_plane.md",
"concepts/self_hosted.md": "concepts/langgraph_self_hosted_data_plane.md",
"tutorials/deployment.md": "concepts/deployment_options.md",
"how-tos/deploy-self-hosted.md": "https://docs.langchain.com/langsmith/platform-setup",
"concepts/self_hosted.md": "https://docs.langchain.com/langsmith/platform-setup",
"tutorials/deployment.md": "https://docs.langchain.com/langsmith/deployments",
# assistant redirects
"cloud/how-tos/assistant_versioning.md": "cloud/how-tos/configuration_cloud.md",
"cloud/concepts/runs.md": "concepts/assistants.md#execution",
"cloud/how-tos/assistant_versioning.md": "https://docs.langchain.com/langsmith/configuration-cloud",
"cloud/concepts/runs.md": "https://docs.langchain.com/langsmith/assistants#execution",
# hitl redirects
"how-tos/wait-user-input-functional.ipynb": "how-tos/use-functional-api.md",
"how-tos/review-tool-calls-functional.ipynb": "how-tos/use-functional-api.md",
"how-tos/create-react-agent-hitl.ipynb": "how-tos/human_in_the_loop/add-human-in-the-loop.md",
"agents/human-in-the-loop.md": "how-tos/human_in_the_loop/add-human-in-the-loop.md",
"how-tos/human_in_the_loop/dynamic_breakpoints.ipynb": "how-tos/human_in_the_loop/breakpoints.md",
"concepts/breakpoints.md": "concepts/human_in_the_loop.md",
"how-tos/human_in_the_loop/breakpoints.md": "how-tos/human_in_the_loop/add-human-in-the-loop.md",
"cloud/how-tos/human_in_the_loop_breakpoint.md": "cloud/how-tos/add-human-in-the-loop.md",
"how-tos/human_in_the_loop/edit-graph-state.ipynb": "how-tos/human_in_the_loop/time-travel.md",
# LGP migration-related redirects - once LG is also migrated, we can add a redirect for the whole site
"concepts/langgraph_platform.md": "https://docs.langchain.com/langgraph-platform",
"concepts/langgraph_components.md": "https://docs.langchain.com/langgraph-platform/components",
"concepts/langgraph_server.md": "https://docs.langchain.com/langgraph-platform/langgraph-server",
"concepts/langgraph_studio.md": "https://docs.langchain.com/langgraph-platform/langgraph-studio",
"cloud/how-tos/invoke_studio.md": "https://docs.langchain.com/langgraph-platform/invoke-studio",
"concepts/langgraph_cli.md": "https://docs.langchain.com/langgraph-platform/langgraph-cli",
"cloud/how-tos/studio/quick_start.md": "https://docs.langchain.com/langgraph-platform/quick-start-studio",
"concepts/sdk.md": "https://docs.langchain.com/langgraph-platform/sdk",
"concepts/auth.md": "https://docs.langchain.com/langgraph-platform/auth",
"concepts/assistants.md": "https://docs.langchain.com/langgraph-platform/assistants",
"concepts/deployment_options.md": "https://docs.langchain.com/langgraph-platform/deployment-options",
"cloud/quick_start.md": "https://docs.langchain.com/langgraph-platform/deployment-quickstart",
"cloud/deployment/setup.md": "https://docs.langchain.com/langgraph-platform/setup-app-requirements-txt",
"concepts/langgraph_self_hosted_data_plane.md": "https://docs.langchain.com/langgraph-platform/self-hosted-data-plane",
"concepts/langgraph_self_hosted_control_plane.md": "https://docs.langchain.com/langgraph-platform/self-hosted-control-plane",
"concepts/langgraph_standalone_container.md": "https://docs.langchain.com/langgraph-platform/standalone-container",
"cloud/deployment/self_hosted_data_plane.md": "https://docs.langchain.com/langgraph-platform/deploy-self-hosted-data-plane",
"cloud/deployment/self_hosted_control_plane.md": "https://docs.langchain.com/langgraph-platform/deploy-self-hosted-control-plane",
"cloud/deployment/standalone_container.md": "https://docs.langchain.com/langgraph-platform/deploy-standalone-container",
"concepts/server-mcp.md": "https://docs.langchain.com/langgraph-platform/server-mcp",
"cloud/reference/cli.md": "https://docs.langchain.com/langgraph-platform/cli",
"cloud/how-tos/use_stream_react.md": "https://docs.langchain.com/langgraph-platform/use-stream-react",
"cloud/how-tos/generative-ui-react.md": "https://docs.langchain.com/langgraph-platform/generative-ui-react",
"how-tos/wait-user-input-functional.ipynb": "https://docs.langchain.com/oss/python/langgraph/functional-api",
"how-tos/review-tool-calls-functional.ipynb": "https://docs.langchain.com/oss/python/langgraph/functional-api",
"how-tos/create-react-agent-hitl.ipynb": "https://docs.langchain.com/oss/python/langgraph/interrupts",
"agents/human-in-the-loop.md": "https://docs.langchain.com/oss/python/langgraph/interrupts",
"how-tos/human_in_the_loop/dynamic_breakpoints.ipynb": "https://docs.langchain.com/oss/python/langgraph/interrupts",
"concepts/breakpoints.md": "https://docs.langchain.com/oss/python/langgraph/interrupts",
"how-tos/human_in_the_loop/breakpoints.md": "https://docs.langchain.com/oss/python/langgraph/interrupts",
"cloud/how-tos/human_in_the_loop_breakpoint.md": "https://docs.langchain.com/langsmith/add-human-in-the-loop",
"how-tos/human_in_the_loop/edit-graph-state.ipynb": "https://docs.langchain.com/oss/python/langgraph/use-time-travel",
# LGP mintlify migration redirects
"examples/index.md": "https://docs.langchain.com/oss/python/learn",
"guides/index.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"concepts/index.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"tutorials/index.md": "https://docs.langchain.com/oss/python/learn",
"llms-txt-overview.md": "https://docs.langchain.com/llms.txt",
"tutorials/rag/langgraph_adaptive_rag.md": "https://docs.langchain.com/oss/python/langgraph/agentic-rag",
"tutorials/multi_agent/multi-agent-collaboration.ipynb": "https://docs.langchain.com/oss/python/langchain/multi-agent",
"how-tos/create-react-agent-manage-message-history.ipynb": "https://docs.langchain.com/oss/python/langgraph/add-memory",
"how-tos/many-tools.ipynb": "https://docs.langchain.com/oss/python/langchain/tools",
"tutorials/customer-support/customer-support.ipynb": "https://docs.langchain.com/oss/python/langgraph/agentic-rag",
"how-tos/react-agent-structured-output.ipynb": "https://docs.langchain.com/oss/python/langchain/agents#structured-output",
"tutorials/code_assistant/langgraph_code_assistant.ipynb": "https://docs.langchain.com/oss/python/langgraph/agentic-rag",
"tutorials/multi_agent/hierarchical_agent_teams.ipynb": "https://docs.langchain.com/oss/python/langchain/supervisor",
"tutorials/auth/getting_started.md": "https://docs.langchain.com/langsmith/auth",
"tutorials/auth/resource_auth.md": "https://docs.langchain.com/langsmith/resource-auth",
"tutorials/auth/add_auth_server.md": "https://docs.langchain.com/langsmith/add-auth-server",
"how-tos/use-remote-graph.md": "https://docs.langchain.com/langsmith/use-remote-graph",
"how-tos/autogen-integration.md": "https://docs.langchain.com/langsmith/autogen-integration",
"how-tos/human_in_the_loop/wait-user-input.ipynb": "https://docs.langchain.com/oss/python/langgraph/interrupts",
"cloud/how-tos/use_stream_react.md": "https://docs.langchain.com/langsmith/use-stream-react",
"cloud/how-tos/generative_ui_react.md": "https://docs.langchain.com/langsmith/generative-ui-react",
"concepts/langgraph_platform.md": "https://docs.langchain.com/langsmith/deployments",
"concepts/langgraph_components.md": "https://docs.langchain.com/langsmith/components",
"concepts/langgraph_server.md": "https://docs.langchain.com/langsmith/agent-server",
"concepts/langgraph_data_plane.md": "https://docs.langchain.com/langsmith/data-plane",
"concepts/langgraph_control_plane.md": "https://docs.langchain.com/langsmith/control-plane",
"concepts/langgraph_cli.md": "https://docs.langchain.com/langsmith/cli",
"concepts/langgraph_studio.md": "https://docs.langchain.com/langsmith/studio",
"cloud/how-tos/studio/quick_start.md": "https://docs.langchain.com/langsmith/quick-start-studio",
"cloud/how-tos/invoke_studio.md": "https://docs.langchain.com/langsmith/use-studio#run-application",
"cloud/how-tos/studio/manage_assistants.md": "https://docs.langchain.com/langsmith/use-studio#manage-assistants",
"cloud/how-tos/threads_studio.md": "https://docs.langchain.com/langsmith/use-studio#manage-threads",
"cloud/how-tos/iterate_graph_studio.md": "https://docs.langchain.com/langsmith/observability-studio#iterate-on-prompts",
"cloud/how-tos/studio/run_evals.md": "https://docs.langchain.com/langsmith/observability-studio#run-experiments-over-a-dataset",
"cloud/how-tos/clone_traces_studio.md": "https://docs.langchain.com/langsmith/observability-studio#debug-langsmith-traces",
"cloud/how-tos/datasets_studio.md": "https://docs.langchain.com/langsmith/observability-studio#add-node-to-dataset",
"concepts/sdk.md": "https://docs.langchain.com/langsmith/sdk",
"concepts/plans.md": "https://langchain.com/pricing",
"concepts/application_structure.md": "https://docs.langchain.com/langsmith/application-structure",
"concepts/scalability_and_resilience.md": "https://docs.langchain.com/langsmith/scalability-and-resilience",
"concepts/auth.md": "https://docs.langchain.com/langsmith/authentication-methods",
"how-tos/auth/custom_auth.md": "https://docs.langchain.com/langsmith/custom-auth",
"how-tos/auth/openapi_security.md": "https://docs.langchain.com/langsmith/openapi-security",
"concepts/assistants.md": "https://docs.langchain.com/langsmith/assistants",
"cloud/how-tos/configuration_cloud.md": "https://docs.langchain.com/langsmith/cloud",
"cloud/how-tos/use_threads.md": "https://docs.langchain.com/langsmith/use-threads",
"cloud/how-tos/background_run.md": "https://docs.langchain.com/langsmith/background-run",
"cloud/how-tos/same-thread.md": "https://docs.langchain.com/langsmith/same-thread",
"cloud/how-tos/stateless_runs.md": "https://docs.langchain.com/langsmith/stateless-runs",
"cloud/how-tos/configurable_headers.md": "https://docs.langchain.com/langsmith/configurable-headers",
"concepts/double_texting.md": "https://docs.langchain.com/langsmith/double-texting",
"cloud/how-tos/interrupt_concurrent.md": "https://docs.langchain.com/langsmith/interrupt-concurrent",
"cloud/how-tos/rollback_concurrent.md": "https://docs.langchain.com/langsmith/rollback-concurrent",
"cloud/how-tos/reject_concurrent.md": "https://docs.langchain.com/langsmith/reject-concurrent",
"cloud/how-tos/enqueue_concurrent.md": "https://docs.langchain.com/langsmith/enqueue-concurrent",
"cloud/concepts/webhooks.md": "https://docs.langchain.com/langsmith/use-webhooks",
"cloud/how-tos/webhooks.md": "https://docs.langchain.com/langsmith/use-webhooks",
"cloud/concepts/cron_jobs.md": "https://docs.langchain.com/langsmith/cron-jobs",
"cloud/how-tos/cron_jobs.md": "https://docs.langchain.com/langsmith/cron-jobs",
"how-tos/http/custom_lifespan.md": "https://docs.langchain.com/langsmith/custom-lifespan",
"how-tos/http/custom_middleware.md": "https://docs.langchain.com/langsmith/custom-middleware",
"how-tos/http/custom_routes.md": "https://docs.langchain.com/langsmith/custom-routes",
"cloud/concepts/data_storage_and_privacy.md": "https://docs.langchain.com/langsmith/data-storage-and-privacy",
"cloud/deployment/semantic_search.md": "https://docs.langchain.com/langsmith/semantic-search",
"how-tos/ttl/configure_ttl.md": "https://docs.langchain.com/langsmith/configure-ttl",
"concepts/deployment_options.md": "https://docs.langchain.com/langsmith/platform-setup",
"cloud/quick_start.md": "https://docs.langchain.com/langsmith/deployment-quickstart",
"cloud/deployment/setup.md": "https://docs.langchain.com/langsmith/setup-app-requirements-txt",
"cloud/deployment/setup_pyproject.md": "https://docs.langchain.com/langsmith/setup-pyproject",
"cloud/deployment/setup_javascript.md": "https://docs.langchain.com/langsmith/setup-javascript",
"cloud/deployment/custom_docker.md": "https://docs.langchain.com/langsmith/custom-docker",
"cloud/deployment/graph_rebuild.md": "https://docs.langchain.com/langsmith/graph-rebuild",
"concepts/langgraph_cloud.md": "https://docs.langchain.com/langsmith/cloud",
"concepts/langgraph_self_hosted_data_plane.md": "https://docs.langchain.com/langsmith/hybrid",
"concepts/langgraph_self_hosted_control_plane.md": "https://docs.langchain.com/langsmith/self-hosted",
"concepts/langgraph_standalone_container.md": "https://docs.langchain.com/langsmith/self-hosted#standalone-server",
"cloud/deployment/cloud.md": "https://docs.langchain.com/langsmith/cloud",
"cloud/deployment/self_hosted_data_plane.md": "https://docs.langchain.com/langsmith/deploy-hybrid",
"cloud/deployment/self_hosted_control_plane.md": "https://docs.langchain.com/langsmith/deploy-self-hosted-full-platform",
"cloud/deployment/standalone_container.md": "https://docs.langchain.com/langsmith/deploy-standalone-server",
"concepts/server-mcp.md": "https://docs.langchain.com/langsmith/server-mcp",
"cloud/how-tos/human_in_the_loop_time_travel.md": "https://docs.langchain.com/langsmith/human-in-the-loop-time-travel",
"cloud/how-tos/add-human-in-the-loop.md": "https://docs.langchain.com/langsmith/add-human-in-the-loop",
"cloud/deployment/egress.md": "https://docs.langchain.com/langsmith/env-var",
"cloud/how-tos/streaming.md": "https://docs.langchain.com/langsmith/streaming",
"cloud/reference/api/api_ref.md": "https://docs.langchain.com/langsmith/server-api-ref",
"cloud/reference/langgraph_server_changelog.md": "https://docs.langchain.com/langsmith/agent-server-changelog",
"cloud/reference/api/api_ref_control_plane.md": "https://docs.langchain.com/langsmith/api-ref-control-plane",
"cloud/reference/cli.md": "https://docs.langchain.com/langsmith/cli",
"cloud/reference/env_var.md": "https://docs.langchain.com/langsmith/env-var",
"troubleshooting/studio.md": "https://docs.langchain.com/langsmith/troubleshooting-studio",
# LangGraph mintlify migration redirects
"index.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"agents/agents.md": "https://docs.langchain.com/oss/python/langchain/agents",
"concepts/why-langgraph.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"tutorials/get-started/1-build-basic-chatbot.md": "https://docs.langchain.com/oss/python/langgraph/quickstart",
"tutorials/get-started/2-add-tools.md": "https://docs.langchain.com/oss/python/langgraph/quickstart",
"tutorials/get-started/3-add-memory.md": "https://docs.langchain.com/oss/python/langgraph/quickstart",
"tutorials/get-started/4-human-in-the-loop.md": "https://docs.langchain.com/oss/python/langgraph/quickstart",
"tutorials/get-started/5-customize-state.md": "https://docs.langchain.com/oss/python/langgraph/quickstart",
"tutorials/get-started/6-time-travel.md": "https://docs.langchain.com/oss/python/langgraph/quickstart",
"tutorials/langsmith/local-server.md": "https://docs.langchain.com/oss/python/langgraph/local-server",
"tutorials/workflows.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
"tutorials/plan-and-execute/plan-and-execute.ipynb": "https://docs.langchain.com/oss/python/langchain/middleware/built-in#to-do-list",
"tutorials/langgraph-platform/local-server/local-server.md": "https://docs.langchain.com/langsmith/local-server",
"concepts/agentic_concepts.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
"guides/index.md": "https://docs.langchain.com/oss/python/langchain/overview",
"agents/overview.md": "https://docs.langchain.com/oss/python/langchain/agents",
"agents/run_agents.md": "https://docs.langchain.com/oss/python/langgraph/quickstart",
"concepts/low_level.md": "https://docs.langchain.com/oss/python/langgraph/graph-api",
"how-tos/graph-api.md": "https://docs.langchain.com/oss/python/langgraph/graph-api",
"how-tos/react-agent-from-scratch.ipynb": "https://docs.langchain.com/oss/python/langchain/quickstart",
"concepts/functional_api.md": "https://docs.langchain.com/oss/python/langgraph/functional-api",
"how-tos/use-functional-api.md": "https://docs.langchain.com/oss/python/langgraph/functional-api",
"concepts/pregel.md": "https://docs.langchain.com/oss/python/langgraph/pregel",
"concepts/streaming.md": "https://docs.langchain.com/oss/python/langgraph/streaming",
"how-tos/streaming.md": "https://docs.langchain.com/oss/python/langgraph/streaming",
"concepts/persistence.md": "https://docs.langchain.com/oss/python/langgraph/persistence",
"concepts/durable_execution.md": "https://docs.langchain.com/oss/python/langgraph/durable-execution",
"concepts/memory.md": "https://docs.langchain.com/oss/python/langgraph/memory",
"how-tos/memory/add-memory.md": "https://docs.langchain.com/oss/python/langgraph/add-memory",
"agents/context.md": "https://docs.langchain.com/oss/python/langgraph/add-memory",
"agents/models.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"concepts/tools.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
"how-tos/tool-calling.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
"concepts/human_in_the_loop.md": "https://docs.langchain.com/oss/python/langgraph/interrupts",
"how-tos/human_in_the_loop/add-human-in-the-loop.md": "https://docs.langchain.com/oss/python/langgraph/interrupts",
"concepts/time-travel.md": "https://docs.langchain.com/oss/python/langgraph/persistence",
"how-tos/human_in_the_loop/time-travel.md": "https://docs.langchain.com/oss/python/langgraph/use-time-travel",
"concepts/subgraphs.md": "https://docs.langchain.com/oss/python/langgraph/use-subgraphs",
"how-tos/subgraph.md": "https://docs.langchain.com/oss/python/langgraph/use-subgraphs",
"concepts/multi_agent.md": "https://docs.langchain.com/oss/python/langgraph/graph-api",
"agents/multi-agent.md": "https://docs.langchain.com/oss/python/langchain/multi-agent",
"how-tos/multi_agent.md": "https://docs.langchain.com/oss/python/langgraph/graph-api",
"concepts/mcp.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"agents/mcp.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"concepts/tracing.md": "https://docs.langchain.com/oss/python/langgraph/observability",
"how-tos/enable-tracing.md": "https://docs.langchain.com/oss/python/langgraph/observability",
"agents/evals.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"examples/index.md": "https://docs.langchain.com/oss/python/langgraph/case-studies",
"concepts/template_applications.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"tutorials/rag/langgraph_agentic_rag.md": "https://docs.langchain.com/oss/python/langgraph/agentic-rag",
"tutorials/multi_agent/agent_supervisor.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
"tutorials/sql/sql-agent.md": "https://docs.langchain.com/oss/python/langgraph/sql-agent",
"agents/ui.md": "https://docs.langchain.com/oss/python/langgraph/ui",
"how-tos/run-id-langsmith.md": "https://docs.langchain.com/oss/python/langgraph/observability",
"troubleshooting/errors/index.md": "https://docs.langchain.com/oss/python/langgraph/common-errors",
"troubleshooting/errors/INVALID_CHAT_HISTORY.md": "https://docs.langchain.com/oss/python/langgraph/INVALID_CHAT_HISTORY",
"troubleshooting/errors/INVALID_LICENSE.md": "https://docs.langchain.com/oss/python/langgraph/common-errors",
"adopters.md": "https://docs.langchain.com/oss/python/langgraph/case-studies",
"concepts/faq.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"agents/prebuilt.md": "https://docs.langchain.com/oss/python/langchain/agents",
"reference/index.md": "https://reference.langchain.com/python/langgraph/",
"reference/graphs.md": "https://reference.langchain.com/python/langgraph/graphs/",
"reference/func.md": "https://reference.langchain.com/python/langgraph/func/",
"reference/pregel.md": "https://reference.langchain.com/python/langgraph/pregel/",
"reference/checkpoints.md": "https://reference.langchain.com/python/langgraph/checkpoints/",
"reference/store.md": "https://reference.langchain.com/python/langgraph/store/",
"reference/cache.md": "https://reference.langchain.com/python/langgraph/cache/",
"reference/types.md": "https://reference.langchain.com/python/langgraph/types/",
"reference/runtime.md": "https://reference.langchain.com/python/langgraph/runtime/",
"reference/config.md": "https://reference.langchain.com/python/langgraph/config/",
"reference/errors.md": "https://reference.langchain.com/python/langgraph/errors/",
"reference/constants.md": "https://reference.langchain.com/python/langgraph/constants/",
"reference/channels.md": "https://reference.langchain.com/python/langgraph/channels/",
"reference/agents.md": "https://reference.langchain.com/python/langgraph/agents/",
"reference/supervisor.md": "https://reference.langchain.com/python/langgraph/supervisor/",
"reference/swarm.md": "https://reference.langchain.com/python/langgraph/swarm/",
"reference/mcp.md": "https://reference.langchain.com/python/langgraph/mcp/",
"cloud/reference/sdk/python_sdk_ref.md": "https://reference.langchain.com/python/langsmith/deployment/sdk/",
"reference/remote_graph.md": "https://reference.langchain.com/python/langsmith/deployment/remote_graph/",
# additional exclude-search entries from mkdocs.yml
"additional-resources/index.md": "https://docs.langchain.com/oss/python/langchain/overview",
"cloud/concepts/cron_jobs.md": "https://docs.langchain.com/langsmith/cron-jobs",
"cloud/concepts/data_storage_and_privacy.md": "https://docs.langchain.com/langsmith/data-storage-and-privacy",
"cloud/concepts/webhooks.md": "https://docs.langchain.com/langsmith/use-webhooks",
"cloud/deployment/cloud.md": "https://docs.langchain.com/langsmith/cloud",
"cloud/deployment/custom_docker.md": "https://docs.langchain.com/langsmith/custom-docker",
"cloud/deployment/egress.md": "https://docs.langchain.com/langsmith/env-var",
"cloud/deployment/graph_rebuild.md": "https://docs.langchain.com/langsmith/graph-rebuild",
"cloud/deployment/self_hosted_control_plane.md": "https://docs.langchain.com/langsmith/platform-setup",
"cloud/deployment/self_hosted_data_plane.md": "https://docs.langchain.com/langsmith/platform-setup",
"cloud/deployment/semantic_search.md": "https://docs.langchain.com/langsmith/semantic-search",
"cloud/deployment/setup_javascript.md": "https://docs.langchain.com/langsmith/setup-javascript",
"cloud/deployment/setup_pyproject.md": "https://docs.langchain.com/langsmith/setup-pyproject",
"cloud/deployment/setup.md": "https://docs.langchain.com/langsmith/setup-app-requirements-txt",
"cloud/deployment/standalone_container.md": "https://docs.langchain.com/langsmith/docker",
"cloud/how-tos/add-human-in-the-loop.md": "https://docs.langchain.com/langsmith/add-human-in-the-loop",
"cloud/how-tos/background_run.md": "https://docs.langchain.com/langsmith/background-run",
"cloud/how-tos/clone_traces_studio.md": "https://docs.langchain.com/langsmith/observability",
"cloud/how-tos/configurable_headers.md": "https://docs.langchain.com/langsmith/configurable-headers",
"cloud/how-tos/configuration_cloud.md": "https://docs.langchain.com/langsmith/configuration-cloud",
"cloud/how-tos/cron_jobs.md": "https://docs.langchain.com/langsmith/cron-jobs",
"cloud/how-tos/datasets_studio.md": "https://docs.langchain.com/langsmith/use-studio",
"cloud/how-tos/enqueue_concurrent.md": "https://docs.langchain.com/langsmith/enqueue-concurrent",
"cloud/how-tos/generative_ui_react.md": "https://docs.langchain.com/langsmith/generative-ui-react",
"cloud/how-tos/human_in_the_loop_time_travel.md": "https://docs.langchain.com/langsmith/human-in-the-loop-time-travel",
"cloud/how-tos/interrupt_concurrent.md": "https://docs.langchain.com/langsmith/interrupt-concurrent",
"cloud/how-tos/invoke_studio.md": "https://docs.langchain.com/langsmith/use-studio",
"cloud/how-tos/iterate_graph_studio.md": "https://docs.langchain.com/langsmith/use-studio",
"cloud/how-tos/reject_concurrent.md": "https://docs.langchain.com/langsmith/reject-concurrent",
"cloud/how-tos/rollback_concurrent.md": "https://docs.langchain.com/langsmith/rollback-concurrent",
"cloud/how-tos/same-thread.md": "https://docs.langchain.com/langsmith/same-thread",
"cloud/how-tos/stateless_runs.md": "https://docs.langchain.com/langsmith/stateless-runs",
"cloud/how-tos/streaming.md": "https://docs.langchain.com/langsmith/streaming",
"cloud/how-tos/studio/manage_assistants.md": "https://docs.langchain.com/langsmith/use-studio",
"cloud/how-tos/studio/quick_start.md": "https://docs.langchain.com/langsmith/quick-start-studio",
"cloud/how-tos/studio/run_evals.md": "https://docs.langchain.com/langsmith/observability",
"cloud/how-tos/threads_studio.md": "https://docs.langchain.com/langsmith/use-threads",
"cloud/how-tos/use_stream_react.md": "https://docs.langchain.com/langsmith/use-stream-react",
"cloud/how-tos/use_threads.md": "https://docs.langchain.com/langsmith/use-threads",
"cloud/how-tos/webhooks.md": "https://docs.langchain.com/langsmith/use-webhooks",
"cloud/quick_start.md": "https://docs.langchain.com/langsmith/deployment-quickstart",
"cloud/reference/api/api_ref_control_plane.md": "https://docs.langchain.com/langsmith/api-ref-control-plane",
"cloud/reference/api/api_ref.md": "https://docs.langchain.com/langsmith/server-api-ref",
"cloud/reference/cli.md": "https://docs.langchain.com/langsmith/cli",
"cloud/reference/env_var.md": "https://docs.langchain.com/langsmith/env-var",
"cloud/reference/langgraph_server_changelog.md": "https://docs.langchain.com/langsmith/agent-server-changelog",
"cloud/reference/sdk/js_ts_sdk_ref.md": "https://reference.langchain.com/javascript/modules/langsmith.html",
"concepts/application_structure.md": "https://docs.langchain.com/langsmith/application-structure",
"concepts/assistants.md": "https://docs.langchain.com/langsmith/assistants",
"concepts/auth.md": "https://docs.langchain.com/langsmith/auth",
"concepts/deployment_options.md": "https://docs.langchain.com/langsmith/deployments",
"concepts/double_texting.md": "https://docs.langchain.com/langsmith/double-texting",
"concepts/faq.md": "https://docs.langchain.com/langsmith/faq",
"concepts/langgraph_cli.md": "https://docs.langchain.com/langsmith/cli",
"concepts/langgraph_cloud.md": "https://docs.langchain.com/langsmith/cloud",
"concepts/langgraph_components.md": "https://docs.langchain.com/langsmith/components",
"concepts/langgraph_control_plane.md": "https://docs.langchain.com/langsmith/control-plane",
"concepts/langgraph_data_plane.md": "https://docs.langchain.com/langsmith/data-plane",
"concepts/langgraph_platform.md": "https://docs.langchain.com/langsmith/home",
"concepts/langgraph_self_hosted_control_plane.md": "https://docs.langchain.com/langsmith/platform-setup",
"concepts/langgraph_self_hosted_data_plane.md": "https://docs.langchain.com/langsmith/platform-setup",
"concepts/langgraph_server.md": "https://docs.langchain.com/langsmith/agent-server",
"concepts/langgraph_standalone_container.md": "https://docs.langchain.com/langsmith/docker",
"concepts/langgraph_studio.md": "https://docs.langchain.com/langsmith/studio",
"concepts/plans.md": "https://docs.langchain.com/langsmith/home",
"concepts/scalability_and_resilience.md": "https://docs.langchain.com/langsmith/scalability-and-resilience",
"concepts/sdk.md": "https://docs.langchain.com/langsmith/sdk",
"concepts/server-mcp.md": "https://docs.langchain.com/langsmith/server-mcp",
"concepts/template_applications.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"concepts/why-langgraph.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"examples/index.md": "https://docs.langchain.com/oss/python/langgraph/case-studies",
"guides/index.md": "https://docs.langchain.com/oss/python/langchain/overview",
"how-tos/auth/custom_auth.md": "https://docs.langchain.com/langsmith/custom-auth",
"how-tos/auth/openapi_security.md": "https://docs.langchain.com/langsmith/openapi-security",
"how-tos/autogen-integration.md": "https://docs.langchain.com/langsmith/autogen-integration",
"how-tos/http/custom_lifespan.md": "https://docs.langchain.com/langsmith/custom-lifespan",
"how-tos/http/custom_middleware.md": "https://docs.langchain.com/langsmith/custom-middleware",
"how-tos/http/custom_routes.md": "https://docs.langchain.com/langsmith/custom-routes",
"how-tos/ttl/configure_ttl.md": "https://docs.langchain.com/langsmith/configure-ttl",
"how-tos/use-remote-graph.md": "https://docs.langchain.com/langsmith/use-remote-graph",
"index.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"snippets/chat_model_tabs.md": "https://docs.langchain.com/oss/python/langchain/overview",
"troubleshooting/errors/GRAPH_RECURSION_LIMIT.md": "https://docs.langchain.com/oss/python/langgraph/GRAPH_RECURSION_LIMIT",
"troubleshooting/errors/index.md": "https://docs.langchain.com/oss/python/langgraph/common-errors",
"troubleshooting/errors/INVALID_CHAT_HISTORY.md": "https://docs.langchain.com/oss/python/langgraph/INVALID_CHAT_HISTORY",
"troubleshooting/errors/INVALID_CONCURRENT_GRAPH_UPDATE.md": "https://docs.langchain.com/oss/python/langgraph/INVALID_CONCURRENT_GRAPH_UPDATE",
"troubleshooting/errors/INVALID_GRAPH_NODE_RETURN_VALUE.md": "https://docs.langchain.com/oss/python/langgraph/INVALID_GRAPH_NODE_RETURN_VALUE",
"troubleshooting/errors/INVALID_LICENSE.md": "https://docs.langchain.com/oss/python/langgraph/common-errors",
"troubleshooting/errors/MULTIPLE_SUBGRAPHS.md": "https://docs.langchain.com/oss/python/langgraph/MULTIPLE_SUBGRAPHS",
"troubleshooting/studio.md": "https://docs.langchain.com/langsmith/troubleshooting-studio",
"tutorials/auth/add_auth_server.md": "https://docs.langchain.com/langsmith/add-auth-server",
"tutorials/auth/getting_started.md": "https://docs.langchain.com/langsmith/auth",
"tutorials/auth/resource_auth.md": "https://docs.langchain.com/langsmith/resource-auth",
"agents/agents.md": "https://docs.langchain.com/oss/python/langchain/agents",
"concepts/why-langgraph.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"tutorials/langsmith/local-server.md": "https://docs.langchain.com/oss/python/langgraph/local-server",
"tutorials/workflows.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
"concepts/agentic_concepts.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
"guides/index.md": "https://docs.langchain.com/oss/python/langchain/overview",
"agents/overview.md": "https://docs.langchain.com/oss/python/langchain/agents",
"concepts/agentic_concepts.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
"agents/run_agents.md": "https://docs.langchain.com/oss/python/langgraph/quickstart",
"concepts/low_level.md": "https://docs.langchain.com/oss/python/langgraph/graph-api",
"how-tos/graph-api.md": "https://docs.langchain.com/oss/python/langgraph/graph-api",
"concepts/functional_api.md": "https://docs.langchain.com/oss/python/langgraph/functional-api",
"how-tos/use-functional-api.md": "https://docs.langchain.com/oss/python/langgraph/functional-api",
"concepts/pregel.md": "https://docs.langchain.com/oss/python/langgraph/pregel",
"concepts/streaming.md": "https://docs.langchain.com/oss/python/langgraph/streaming",
"how-tos/streaming.md": "https://docs.langchain.com/oss/python/langgraph/streaming",
"concepts/persistence.md": "https://docs.langchain.com/oss/python/langgraph/persistence",
"concepts/durable_execution.md": "https://docs.langchain.com/oss/python/langgraph/durable-execution",
"concepts/memory.md": "https://docs.langchain.com/oss/python/langgraph/memory",
"how-tos/memory/add-memory.md": "https://docs.langchain.com/oss/python/langgraph/add-memory",
"agents/context.md": "https://docs.langchain.com/oss/python/langgraph/add-memory",
"agents/models.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"concepts/tools.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
"how-tos/tool-calling.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
"concepts/human_in_the_loop.md": "https://docs.langchain.com/oss/python/langgraph/interrupts",
"how-tos/human_in_the_loop/add-human-in-the-loop.md": "https://docs.langchain.com/oss/python/langgraph/interrupts",
"concepts/time-travel.md": "https://docs.langchain.com/oss/python/langgraph/persistence",
"how-tos/human_in_the_loop/time-travel.md": "https://docs.langchain.com/oss/python/langgraph/use-time-travel",
"concepts/subgraphs.md": "https://docs.langchain.com/oss/python/langgraph/use-subgraphs",
"how-tos/subgraph.md": "https://docs.langchain.com/oss/python/langgraph/use-subgraphs",
"concepts/multi_agent.md": "https://docs.langchain.com/oss/python/langgraph/graph-api",
"agents/multi-agent.md": "https://docs.langchain.com/oss/python/langchain/multi-agent",
"how-tos/multi_agent.md": "https://docs.langchain.com/oss/python/langgraph/graph-api",
"concepts/mcp.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"agents/mcp.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"concepts/tracing.md": "https://docs.langchain.com/oss/python/langgraph/observability",
"how-tos/enable-tracing.md": "https://docs.langchain.com/oss/python/langgraph/observability",
"agents/evals.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"examples/index.md": "https://docs.langchain.com/oss/python/langgraph/case-studies",
"concepts/template_applications.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"tutorials/rag/langgraph_agentic_rag.md": "https://docs.langchain.com/oss/python/langgraph/agentic-rag",
"tutorials/multi_agent/agent_supervisor.md": "https://docs.langchain.com/oss/python/langgraph/workflows-agents",
"tutorials/sql/sql-agent.md": "https://docs.langchain.com/oss/python/langgraph/sql-agent",
"agents/ui.md": "https://docs.langchain.com/oss/python/langgraph/ui",
"how-tos/run-id-langsmith.md": "https://docs.langchain.com/oss/python/langgraph/observability",
"troubleshooting/errors/index.md": "https://docs.langchain.com/oss/python/langgraph/common-errors",
"troubleshooting/errors/GRAPH_RECURSION_LIMIT.md": "https://docs.langchain.com/oss/python/langgraph/GRAPH_RECURSION_LIMIT",
"troubleshooting/errors/INVALID_CONCURRENT_GRAPH_UPDATE.md": "https://docs.langchain.com/oss/python/langgraph/INVALID_CONCURRENT_GRAPH_UPDATE",
"troubleshooting/errors/INVALID_GRAPH_NODE_RETURN_VALUE.md": "https://docs.langchain.com/oss/python/langgraph/INVALID_GRAPH_NODE_RETURN_VALUE",
"troubleshooting/errors/MULTIPLE_SUBGRAPHS.md": "https://docs.langchain.com/oss/python/langgraph/MULTIPLE_SUBGRAPHS",
"troubleshooting/errors/INVALID_CHAT_HISTORY.md": "https://docs.langchain.com/oss/python/langgraph/INVALID_CHAT_HISTORY",
"troubleshooting/errors/INVALID_LICENSE.md": "https://docs.langchain.com/oss/python/langgraph/common-errors",
"adopters.md": "https://docs.langchain.com/oss/python/langgraph/case-studies",
"concepts/faq.md": "https://docs.langchain.com/oss/python/langgraph/overview",
"agents/prebuilt.md": "https://docs.langchain.com/oss/python/langchain/agents",
}
@@ -505,17 +805,131 @@ def on_post_page(html: str, page: Page, config: MkDocsConfig) -> str:
# Create HTML files for redirects after site dir has been built
def on_post_build(config):
use_directory_urls = config.get("use_directory_urls")
site_dir = config["site_dir"]
# Track which paths have explicit redirects
redirected_paths = set()
# Collect all existing HTML files in the site
all_html_files = set()
for root, dirs, files in os.walk(site_dir):
for file in files:
if file.endswith(".html"):
# Get relative path from site_dir
html_path = os.path.relpath(os.path.join(root, file), site_dir)
# Normalize path separators to forward slashes
html_path = html_path.replace(os.sep, "/")
all_html_files.add(html_path)
# Process explicit redirects from REDIRECT_MAP
for page_old, page_new in REDIRECT_MAP.items():
# Convert .ipynb to .md for path calculation
page_old = page_old.replace(".ipynb", ".md")
page_new = page_new.replace(".ipynb", ".md")
page_new_before_hash, hash, suffix = page_new.partition("#")
old_html_path = File(page_old, "", "", use_directory_urls).dest_path.replace(
os.sep, "/"
)
new_html_path = File(page_new_before_hash, "", "", True).url
new_html_path = (
posixpath.relpath(new_html_path, start=posixpath.dirname(old_html_path))
+ hash
+ suffix
)
_write_html(config["site_dir"], old_html_path, new_html_path)
# Calculate the HTML path for the old page (whether it exists or not)
if use_directory_urls:
# With directory URLs: /path/to/page/ becomes /path/to/page/index.html
if page_old.endswith(".md"):
old_html_path = page_old[:-3] + "/index.html"
else:
old_html_path = page_old + "/index.html"
else:
# Without directory URLs: /path/to/page.md becomes /path/to/page.html
if page_old.endswith(".md"):
old_html_path = page_old[:-3] + ".html"
else:
old_html_path = page_old + ".html"
# Track this path as redirected
redirected_paths.add(old_html_path)
if isinstance(page_new, str) and page_new.startswith("http"):
# Handle external redirects
_write_html(site_dir, old_html_path, page_new)
else:
# Handle internal redirects
page_new = page_new.replace(".ipynb", ".md")
page_new_before_hash, hash, suffix = page_new.partition("#")
# Try to get the new path using File class, but fallback to manual calculation
try:
new_html_path = File(page_new_before_hash, "", "", True).url
new_html_path = (
posixpath.relpath(new_html_path, start=posixpath.dirname(old_html_path))
+ hash
+ suffix
)
except:
# Fallback: calculate relative path manually
if use_directory_urls:
if page_new_before_hash.endswith(".md"):
new_html_path = page_new_before_hash[:-3] + "/"
else:
new_html_path = page_new_before_hash + "/"
else:
if page_new_before_hash.endswith(".md"):
new_html_path = page_new_before_hash[:-3] + ".html"
else:
new_html_path = page_new_before_hash + ".html"
new_html_path += hash + suffix
_write_html(site_dir, old_html_path, new_html_path)
# Create catch-all redirects for any HTML files not explicitly redirected
catchall_url = "https://docs.langchain.com/oss/python/langgraph/overview"
for html_file in all_html_files:
# Skip if this file is already explicitly redirected
if html_file in redirected_paths:
continue
# Skip the root index.html (we handle that separately)
if html_file == "index.html":
continue
# Skip reference documentation (keep those accessible)
if html_file.startswith("reference/"):
continue
# Create redirect for this unmapped file
_write_html(site_dir, html_file, catchall_url)
# Create root index.html redirect
root_redirect_html = """<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Redirecting to LangGraph Documentation</title>
<link rel="canonical" href="https://docs.langchain.com/oss/python/langgraph/overview">
<meta name="robots" content="noindex">
<script>var anchor=window.location.hash.substr(1);location.href="https://docs.langchain.com/oss/python/langgraph/overview"+(anchor?"#"+anchor:"")</script>
<meta http-equiv="refresh" content="0; url=https://docs.langchain.com/oss/python/langgraph/overview">
</head>
<body>
<h1>Documentation has moved</h1>
<p>The LangGraph documentation has moved to <a href="https://docs.langchain.com/oss/python/langgraph/overview">docs.langchain.com</a>.</p>
<p>Redirecting you now...</p>
</body>
</html>
"""
root_index_path = os.path.join(site_dir, "index.html")
with open(root_index_path, "w", encoding="utf-8") as f:
f.write(root_redirect_html)
# Create server-side catch-all redirect file for Netlify/Cloudflare Pages
# This handles any pages not explicitly mapped in REDIRECT_MAP
# Note: This won't work on GitHub Pages, but kept for potential future use
redirects_content = """# Netlify/Cloudflare Pages redirect rules
# Specific redirects are handled by individual HTML redirect pages
# This is the catch-all for any unmapped pages
# Exclude reference docs from catch-all
/reference/* 200
# Catch-all: redirect any page not explicitly mapped
/* https://docs.langchain.com/oss/python/langgraph/overview 301
"""
redirects_path = os.path.join(site_dir, "_redirects")
with open(redirects_path, "w", encoding="utf-8") as f:
f.write(redirects_content)
@@ -20,16 +20,19 @@ class Package(TypedDict):
description: str
"""A brief description of what the package does."""
class ResolvedPackage(Package):
weekly_downloads: int | None
"""The weekly download count of the package."""
language: str
"""The language of the package. (either 'python' or 'js')"""
HERE = pathlib.Path(__file__).parent
PACKAGES_FILE = HERE / "packages.yml"
PACKAGES = yaml.safe_load(PACKAGES_FILE.read_text())["packages"]
def _get_pypi_downloads(package: Package) -> int:
"""Retrieve the weekly download count for a package from PyPIStats."""
@@ -72,7 +75,8 @@ def _get_pypi_downloads(package: Package) -> int:
return sum(entry["downloads"] for entry in sorted_data[:7])
else:
return None
def _get_npm_downloads(package: Package) -> int:
"""Retrieve the weekly download count for a package on the npm registry."""
@@ -82,14 +86,18 @@ def _get_npm_downloads(package: Package) -> int:
npm_response = requests.get(npm_url)
npm_response.raise_for_status()
except requests.exceptions.HTTPError:
raise AssertionError(f"Package {package['name']} does not exist on npm registry")
raise AssertionError(
f"Package {package['name']} does not exist on npm registry"
)
npm_data = npm_response.json()
# Retrieve the first publish date using the 'created' timestamp from the 'time' field.
created_str = npm_data.get("time", {}).get("created")
if created_str is None:
raise AssertionError(f"Package {package['name']} has no creation time in registry data")
raise AssertionError(
f"Package {package['name']} has no creation time in registry data"
)
# Remove the trailing 'Z' if present and parse the ISO format timestamp
first_publish_date = datetime.fromisoformat(created_str.rstrip("Z"))
@@ -103,7 +111,10 @@ def _get_npm_downloads(package: Package) -> int:
else:
return None
def _get_weekly_downloads(packages: dict[str, list[Package]], fake: bool) -> list[ResolvedPackage]:
def _get_weekly_downloads(
packages: dict[str, list[Package]], fake: bool
) -> list[ResolvedPackage]:
"""Retrieve the weekly download count for a dictionary of python or js packages."""
resolved_packages: list[ResolvedPackage] = []
@@ -131,7 +142,7 @@ def _get_weekly_downloads(packages: dict[str, list[Package]], fake: bool) -> lis
num_downloads = _get_npm_downloads(package)
else:
num_downloads = None
resolved_packages.append(
{
"name": package["name"],
@@ -145,12 +156,13 @@ def _get_weekly_downloads(packages: dict[str, list[Package]], fake: bool) -> lis
return resolved_packages
def main(output_file: str, fake: bool) -> None:
"""Main function to generate package download information.
Args:
output_file: Path to the output YAML file.
fake: If True, use fake download counts for testing purposes.
fake: If `True`, use fake download counts for testing purposes.
"""
resolved_packages: list[ResolvedPackage] = _get_weekly_downloads(PACKAGES, fake)
+2 -2
View File
@@ -29,7 +29,7 @@ pip install -U langgraph "langchain[anthropic]"
!!! info
LangChain is installed so the agent can call the [model](https://python.langchain.com/docs/integrations/chat/).
`langchain[anthropic]` is installed so the agent can call the [model](https://python.langchain.com/docs/integrations/chat/).
:::
@@ -41,7 +41,7 @@ npm install @langchain/langgraph @langchain/core @langchain/anthropic
!!! info
LangChain is installed so the agent can call the [model](https://js.langchain.com/docs/integrations/chat/).
`@langchain/core` `@langchain/anthropic` are installed so the agent can call the [model](https://js.langchain.com/docs/integrations/chat/).
:::
+6 -6
View File
@@ -3,11 +3,11 @@
**Context engineering** is the practice of building dynamic systems that provide the right information and tools, in the right format, so that an AI application can accomplish a task. Context can be characterized along two key dimensions:
1. By **mutability**:
- **Static context**: Immutable data that doesn't change during execution (e.g., user metadata, database connections, tools)
- **Dynamic context**: Mutable data that evolves as the application runs (e.g., conversation history, intermediate results, tool call observations)
- **Static context**: Immutable data that doesn't change during execution (e.g., user metadata, database connections, tools)
- **Dynamic context**: Mutable data that evolves as the application runs (e.g., conversation history, intermediate results, tool call observations)
2. By **lifetime**:
- **Runtime context**: Data scoped to a single run or invocation
- **Cross-conversation context**: Data that persists across multiple conversations or sessions
- **Runtime context**: Data scoped to a single run or invocation
- **Cross-conversation context**: Data that persists across multiple conversations or sessions
!!! tip "Runtime context vs LLM context"
@@ -33,7 +33,7 @@ LangGraph provides three ways to manage context, which combines the mutability a
**Static runtime context** represents immutable data like user metadata, tools, and database connections that are passed to an application at the start of a run via the `context` argument to `invoke`/`stream`. This data does not change during execution.
!!! version-added "New in LangGraph v0.6: `context` replaces `config['configurable']`"
!!! version-added "Added in version 0.6.0: `context` replaces `config['configurable']`"
Runtime context is now passed to the `context` argument of `invoke`/`stream`,
which replaces the previous pattern of passing application configuration to `config['configurable']`.
@@ -90,7 +90,7 @@ graph.invoke( # (1)!
from langgraph.runtime import Runtime
# highlight-next-line
def node(state: State, config: Runtime[ContextSchema]):
def node(state: State, runtime: Runtime[ContextSchema]):
user_name = runtime.context.user_name
...
```
+74
View File
@@ -145,6 +145,76 @@ const agent = createReactAgent({
:::
:::python
### Dynamic model selection
Pass a callable function to `create_react_agent` to dynamically select the model at runtime. This is useful for scenarios where you want to choose a model based on user input, configuration settings, or other runtime conditions.
The selector function must return a chat model. If you're using tools, you must bind the tools to the model within the selector function.
```python
from dataclasses import dataclass
from typing import Literal
from langchain.chat_models import init_chat_model
from langchain_core.language_models import BaseChatModel
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent
from langgraph.prebuilt.chat_agent_executor import AgentState
from langgraph.runtime import Runtime
@tool
def weather() -> str:
"""Returns the current weather conditions."""
return "It's nice and sunny."
# Define the runtime context
@dataclass
class CustomContext:
provider: Literal["anthropic", "openai"]
# Initialize models
openai_model = init_chat_model("openai:gpt-4o")
anthropic_model = init_chat_model("anthropic:claude-sonnet-4-20250514")
# Selector function for model choice
def select_model(state: AgentState, runtime: Runtime[CustomContext]) -> BaseChatModel:
if runtime.context.provider == "anthropic":
model = anthropic_model
elif runtime.context.provider == "openai":
model = openai_model
else:
raise ValueError(f"Unsupported provider: {runtime.context.provider}")
# With dynamic model selection, you must bind tools explicitly
return model.bind_tools([weather])
# Create agent with dynamic model selection
agent = create_react_agent(select_model, tools=[weather])
# Invoke with context to select model
output = agent.invoke(
{
"messages": [
{
"role": "user",
"content": "Which model is handling this?",
}
]
},
context=CustomContext(provider="openai"),
)
print(output["messages"][-1].text())
```
!!! version-added "Added in version 0.6.0"
:::
## Advanced model configuration
### Disable streaming
@@ -281,11 +351,13 @@ If your desired LLM isn't officially supported by LangChain, consider these opti
:::python
1. **Implement a custom LangChain chat model**: Create a model conforming to the [LangChain chat model interface](https://python.langchain.com/docs/how_to/custom_chat_model/). This enables full compatibility with LangGraph's agents and workflows but requires understanding of the LangChain framework.
:::
:::js
1. **Implement a custom LangChain chat model**: Create a model conforming to the [LangChain chat model interface](https://js.langchain.com/docs/how_to/custom_chat/). This enables full compatibility with LangGraph's agents and workflows but requires understanding of the LangChain framework.
:::
2. **Direct invocation with custom streaming**: Use your model directly by [adding custom streaming logic](../how-tos/streaming.md#use-with-any-llm) with `StreamWriter`.
@@ -301,6 +373,7 @@ If your desired LLM isn't officially supported by LangChain, consider these opti
- [Force model to call a specific tool](https://python.langchain.com/docs/how_to/tool_choice/)
- [All chat model how-to guides](https://python.langchain.com/docs/how_to/#chat-models)
- [Chat model integrations](https://python.langchain.com/docs/integrations/chat/)
:::
:::js
@@ -311,4 +384,5 @@ If your desired LLM isn't officially supported by LangChain, consider these opti
- [Force model to call a specific tool](https://js.langchain.com/docs/how_to/tool_choice/)
- [All chat model how-to guides](https://js.langchain.com/docs/how_to/#chat-models)
- [Chat model integrations](https://js.langchain.com/docs/integrations/chat/)
:::
+9 -8
View File
@@ -367,13 +367,13 @@ To implement handoffs with `createReactAgent`, you need to:
3. Define a parent graph that contains individual agents as nodes:
```typescript
import { StateGraph, MessagesZodState } from "@langchain/langgraph";
const multiAgentGraph = new StateGraph(MessagesZodState)
.addNode("flight_assistant", flightAssistant)
.addNode("hotel_assistant", hotelAssistant)
// ...
```
```typescript
import { StateGraph, MessagesZodState } from "@langchain/langgraph";
const multiAgentGraph = new StateGraph(MessagesZodState)
.addNode("flight_assistant", flightAssistant)
.addNode("hotel_assistant", hotelAssistant)
// ...
```
:::
@@ -619,7 +619,8 @@ for await (const chunk of multiAgentGraph.stream({
3. Name of the agent or node to hand off to.
4. Take the agent's messages and **add** them to the parent's **state** as part of the handoff. The next agent will see the parent state.
5. Indicate to LangGraph that we need to navigate to agent node in a **parent** multi-agent graph.
:::
:::
!!! Note
+1 -1
View File
@@ -159,7 +159,7 @@ function generateCodeSnippet({ tools, pre, post, response }) {
if (post) lines.push(" post_model_hook=post_model_hook,");
if (response) lines.push(" response_format=ResponseFormat,");
lines.push(")", "", "agent.get_graph().draw_mermaid_png()");
lines.push(")", "", "# Visualize the graph", "# For Jupyter or GUI environments:", "agent.get_graph().draw_mermaid_png()", "", "# To save PNG to file:", "png_data = agent.get_graph().draw_mermaid_png()", "with open(\"graph.png\", \"wb\") as f:", " f.write(png_data)", "", "# For terminal/ASCII output:", "agent.get_graph().draw_ascii()");
return lines.join("\n");
}
+15
View File
@@ -0,0 +1,15 @@
## Cron jobs
There are many situations in which it is useful to run an assistant on a schedule.
For example, say that you're building an assistant that runs daily and sends an email summary
of the day's news. You could use a cron job to run the assistant every day at 8:00 PM.
LangGraph Platform supports cron jobs, which run on a user-defined schedule. The user specifies a schedule, an assistant, and some input. After that, on the specified schedule, the server will:
- Create a new thread with the specified assistant
- Send the specified input to that thread
Note that this sends the same input to the thread every time. See the [how-to guide](../../cloud/how-tos/cron_jobs.md) for creating cron jobs.
The LangGraph Platform API provides several endpoints for creating and managing cron jobs. See the [API reference](../../cloud/reference/api/api_ref.html#tag/runscreate/POST/threads/{thread_id}/runs/crons) for more details.
@@ -0,0 +1,54 @@
# Data Storage and Privacy
This document describes how data is processed in the LangGraph CLI and the LangGraph Server for both the in-memory server (`langgraph dev`) and the local Docker server (`langgraph up`). It also describes what data is tracked when interacting with the hosted LangGraph Studio frontend.
## CLI
LangGraph **CLI** is the command-line interface for building and running LangGraph applications; see the [CLI guide](../../concepts/langgraph_cli.md) to learn more.
By default, calls to most CLI commands log a single analytics event upon invocation. This helps us better prioritize improvements to the CLI experience. Each telemetry event contains the calling process's OS, OS version, Python version, the CLI version, the command name (`dev`, `up`, `run`, etc.), and booleans representing whether a flag was passed to the command. You can see the full analytics logic [here](https://github.com/langchain-ai/langgraph/blob/main/libs/cli/langgraph_cli/analytics.py).
You can disable all CLI telemetry by setting `LANGGRAPH_CLI_NO_ANALYTICS=1`.
## LangGraph Server (in-memory & docker)
The [LangGraph Server](../../concepts/langgraph_server.md) provides a durable execution runtime that relies on persisting checkpoints of your application state, long-term memories, thread metadata, assistants, and similar resources to the local file system or a database. Unless you have deliberately customized the storage location, this information is either written to local disk (for `langgraph dev`) or a PostgreSQL database (for `langgraph up` and in all deployments).
### LangSmith Tracing
When running the LangGraph server (either in-memory or in Docker), LangSmith tracing may be enabled to facilitate faster debugging and offer observability of graph state and LLM prompts in production. You can always disable tracing by setting `LANGSMITH_TRACING=false` in your server's runtime environment.
### In-memory development server (`langgraph dev`)
`langgraph dev` runs an [in-memory development server](../../tutorials/langgraph-platform/local-server.md) as a single Python process, designed for quick development and testing. It saves all checkpointing and memory data to disk within a `.langgraph_api` directory in the current working directory. Apart from the telemetry data described in the [CLI](#cli) section, no data leaves the machine unless you have enabled tracing or your graph code explicitly contacts an external service.
### Standalone Container (`langgraph up`)
`langgraph up` builds your local package into a Docker image and runs the server as a [standalone container](../../concepts/deployment_options.md#standalone-container) consisting of three containers: the API server, a PostgreSQL container, and a Redis container. All persistent data (checkpoints, assistants, etc.) are stored in the PostgreSQL database. Redis is used as a pubsub connection for real-time streaming of events. You can encrypt all checkpoints before saving to the database by setting a valid `LANGGRAPH_AES_KEY` environment variable. You can also specify [TTLs](../../how-tos/ttl/configure_ttl.md) for checkpoints and cross-thread memories in `langgraph.json` to control how long data is stored. All persisted threads, memories, and other data can be deleted via the relevant API endpoints.
Additional API calls are made to confirm that the server has a valid license and to track the number of executed runs and tasks. Periodically, the API server validates the provided license key (or API key).
If you've disabled [tracing](#langsmith-tracing), no user data is persisted externally unless your graph code explicitly contacts an external service.
## Studio
[LangGraph Studio](../../concepts/langgraph_studio.md) is a graphical interface for interacting with your LangGraph server. It does not persist any private data (the data you send to your server is not sent to LangSmith). Though the studio interface is served at [smith.langchain.com](https://smith.langchain.com), it is run in your browser and connects directly to your local LangGraph server so that no data needs to be sent to LangSmith.
If you are logged in, LangSmith does collect some usage analytics to help improve studio's user experience. This includes:
- Page visits and navigation patterns
- User actions (button clicks)
- Browser type and version
- Screen resolution and viewport size
Importantly, no application data or code (or other sensitive configuration details) are collected. All of that is stored in the persistence layer of your LangGraph server. When using Studio anonymously, no account creation is required and usage analytics are not collected.
## Quick reference
In summary, you can opt-out of server-side telemetry by turning off CLI analytics and disabling tracing.
| Variable | Purpose | Default |
| ------------------------------ | ------------------------- | -------------------------------- |
| `LANGGRAPH_CLI_NO_ANALYTICS=1` | Disable CLI analytics | Analytics enabled |
| `LANGSMITH_API_KEY` | Enable LangSmith tracing | Tracing disabled |
| `LANGSMITH_TRACING=false` | Disable LangSmith tracing | Depends on environment |
+7
View File
@@ -0,0 +1,7 @@
# Webhooks
Webhooks enable event-driven communication from your LangGraph Platform application to external services. For example, you may want to issue an update to a separate service once an API call to LangGraph Platform has finished running.
Many LangGraph Platform endpoints accept a `webhook` parameter. If this parameter is specified by an endpoint that can accept POST requests, LangGraph Platform will send a request at the completion of a run.
See the corresponding [how-to guide](../../cloud/how-tos/webhooks.md) for more detail.
+128
View File
@@ -0,0 +1,128 @@
# How to Deploy to Cloud SaaS
Before deploying, review the [conceptual guide for the Cloud SaaS](../../concepts/langgraph_cloud.md) deployment option.
## Prerequisites
1. LangGraph Platform applications are deployed from GitHub repositories. Configure and upload a LangGraph Platform application to a GitHub repository in order to deploy it to LangGraph Platform.
1. [Verify that the LangGraph API runs locally](../../tutorials/langgraph-platform/local-server.md). If the API does not run successfully (i.e. `langgraph dev`), deploying to LangGraph Platform will fail as well.
## Create New Deployment
Starting from the <a href="https://smith.langchain.com/" target="_blank">LangSmith UI</a>...
1. In the left-hand navigation panel, select `LangGraph Platform`. The `LangGraph Platform` view contains a list of existing LangGraph Platform deployments.
1. In the top-right corner, select `+ New Deployment` to create a new deployment.
1. In the `Create New Deployment` panel, fill out the required fields.
1. `Deployment details`
1. Select `Import from GitHub` and follow the GitHub OAuth workflow to install and authorize LangChain's `hosted-langserve` GitHub app to access the selected repositories. After installation is complete, return to the `Create New Deployment` panel and select the GitHub repository to deploy from the dropdown menu. **Note**: The GitHub user installing LangChain's `hosted-langserve` GitHub app must be an [owner](https://docs.github.com/en/organizations/managing-peoples-access-to-your-organization-with-roles/roles-in-an-organization#organization-owners) of the organization or account.
1. Specify a name for the deployment.
1. Specify the desired `Git Branch`. A deployment is linked to a branch. When a new revision is created, code for the linked branch will be deployed. The branch can be updated later in the [Deployment Settings](#deployment-settings).
1. Specify the full path to the [LangGraph API config file](../reference/cli.md#configuration-file) including the file name. For example, if the file `langgraph.json` is in the root of the repository, simply specify `langgraph.json`.
1. Check/uncheck checkbox to `Automatically update deployment on push to branch`. If checked, the deployment will automatically be updated when changes are pushed to the specified `Git Branch`. This setting can be enabled/disabled later in the [Deployment Settings](#deployment-settings).
1. Select the desired `Deployment Type`.
1. `Development` deployments are meant for non-production use cases and are provisioned with minimal resources.
1. `Production` deployments can serve up to 500 requests/second and are provisioned with highly available storage with automatic backups.
1. Determine if the deployment should be `Shareable through LangGraph Studio`.
1. If unchecked, the deployment will only be accessible with a valid LangSmith API key for the workspace.
1. If checked, the deployment will be accessible through LangGraph Studio to any LangSmith user. A direct URL to LangGraph Studio for the deployment will be provided to share with other LangSmith users.
1. Specify `Environment Variables` and secrets. See the [Environment Variables reference](../reference/env_var.md) to configure additional variables for the deployment.
1. Sensitive values such as API keys (e.g. `OPENAI_API_KEY`) should be specified as secrets.
1. Additional non-secret environment variables can be specified as well.
1. A new LangSmith `Tracing Project` is automatically created with the same name as the deployment.
1. In the top-right corner, select `Submit`. After a few seconds, the `Deployment` view appears and the new deployment will be queued for provisioning.
## Create New Revision
When [creating a new deployment](#create-new-deployment), a new revision is created by default. Subsequent revisions can be created to deploy new code changes.
Starting from the <a href="https://smith.langchain.com/" target="_blank">LangSmith UI</a>...
1. In the left-hand navigation panel, select `LangGraph Platform`. The `LangGraph Platform` view contains a list of existing LangGraph Platform deployments.
1. Select an existing deployment to create a new revision for.
1. In the `Deployment` view, in the top-right corner, select `+ New Revision`.
1. In the `New Revision` modal, fill out the required fields.
1. Specify the full path to the [LangGraph API config file](../reference/cli.md#configuration-file) including the file name. For example, if the file `langgraph.json` is in the root of the repository, simply specify `langgraph.json`.
1. Determine if the deployment should be `Shareable through LangGraph Studio`.
1. If unchecked, the deployment will only be accessible with a valid LangSmith API key for the workspace.
1. If checked, the deployment will be accessible through LangGraph Studio to any LangSmith user. A direct URL to LangGraph Studio for the deployment will be provided to share with other LangSmith users.
1. Specify `Environment Variables` and secrets. Existing secrets and environment variables are prepopulated. See the [Environment Variables reference](../reference/env_var.md) to configure additional variables for the revision.
1. Add new secrets or environment variables.
1. Remove existing secrets or environment variables.
1. Update the value of existing secrets or environment variables.
1. Select `Submit`. After a few seconds, the `New Revision` modal will close and the new revision will be queued for deployment.
## View Build and Server Logs
Build and server logs are available for each revision.
Starting from the `LangGraph Platform` view...
1. Select the desired revision from the `Revisions` table. A panel slides open from the right-hand side and the `Build` tab is selected by default, which displays build logs for the revision.
1. In the panel, select the `Server` tab to view server logs for the revision. Server logs are only available after a revision has been deployed.
1. Within the `Server` tab, adjust the date/time range picker as needed. By default, the date/time range picker is set to the `Last 7 days`.
## View Deployment Metrics
Starting from the <a href="https://smith.langchain.com/" target="_blank">LangSmith UI</a>...
1. In the left-hand navigation panel, select `LangGraph Platform`. The `LangGraph Platform` view contains a list of existing LangGraph Platform deployments.
1. Select an existing deployment to monitor.
1. Select the `Monitoring` tab to view the deployment metrics. See a list of [all available metrics](../../concepts/langgraph_control_plane.md#monitoring).
1. Within the `Monitoring` tab, use the date/time range picker as needed. By default, the date/time range picker is set to the `Last 15 minutes`.
## Interrupt Revision
Interrupting a revision will stop deployment of the revision.
!!! warning "Undefined Behavior"
Interrupted revisions have undefined behavior. This is only useful if you need to deploy a new revision and you already have a revision "stuck" in progress. In the future, this feature may be removed.
Starting from the `LangGraph Platform` view...
1. Select the menu icon (three dots) on the right-hand side of the row for the desired revision from the `Revisions` table.
1. Select `Interrupt` from the menu.
1. A modal will appear. Review the confirmation message. Select `Interrupt revision`.
## Delete Deployment
Starting from the <a href="https://smith.langchain.com/" target="_blank">LangSmith UI</a>...
1. In the left-hand navigation panel, select `LangGraph Platform`. The `LangGraph Platform` view contains a list of existing LangGraph Platform deployments.
1. Select the menu icon (three dots) on the right-hand side of the row for the desired deployment and select `Delete`.
1. A `Confirmation` modal will appear. Select `Delete`.
## Deployment Settings
Starting from the `LangGraph Platform` view...
1. In the top-right corner, select the gear icon (`Deployment Settings`).
1. Update the `Git Branch` to the desired branch.
1. Check/uncheck checkbox to `Automatically update deployment on push to branch`.
1. Branch creation/deletion and tag creation/deletion events will not trigger an update. Only pushes to an existing branch will trigger an update.
1. Pushes in quick succession to a branch will queue subsequent updates. Once a build completes, the most recent commit will begin building and the other queued builds will be skipped.
## Add or Remove GitHub Repositories
After installing and authorizing LangChain's `hosted-langserve` GitHub app, repository access for the app can be modified to add new repositories or remove existing repositories. If a new repository is created, it may need to be added explicitly.
1. From the GitHub profile, navigate to `Settings` > `Applications` > `hosted-langserve` > click `Configure`.
1. Under `Repository access`, select `All repositories` or `Only select repositories`. If `Only select repositories` is selected, new repositories must be explicitly added.
1. Click `Save`.
1. When creating a new deployment, the list of GitHub repositories in the dropdown menu will be updated to reflect the repository access changes.
## Whitelisting IP Addresses
All traffic from `LangGraph Platform` deployments created after January 6th 2025 will come through a NAT gateway.
This NAT gateway will have several static ip addresses depending on the region you are deploying in. Refer to the table below for the list of IP addresses to whitelist:
| US | EU |
|----------------|-----------------|
| 35.197.29.146 | 34.90.213.236 |
| 34.145.102.123 | 34.13.244.114 |
| 34.169.45.153 | 34.32.180.189 |
| 34.82.222.17 | 34.34.69.108 |
| 35.227.171.135 | 34.32.145.240 |
| 34.169.88.30 | 34.90.157.44 |
| 34.19.93.202 | 34.141.242.180 |
| 34.19.34.50 | 34.32.141.108 |
@@ -0,0 +1,19 @@
# How to customize Dockerfile
Users can add an array of additional lines to add to the Dockerfile following the import from the parent LangGraph image. In order to do this, you simply need to modify your `langgraph.json` file by passing in the commands you want run to the `dockerfile_lines` key. For example, if we wanted to use `Pillow` in our graph you would need to add the following dependencies:
```
{
"dependencies": ["."],
"graphs": {
"openai_agent": "./openai_agent.py:agent",
},
"env": "./.env",
"dockerfile_lines": [
"RUN apt-get update && apt-get install -y libjpeg-dev zlib1g-dev libpng-dev",
"RUN pip install Pillow"
]
}
```
This would install the system packages required to use Pillow if we were working with `jpeg` or `png` image formats.
+119
View File
@@ -0,0 +1,119 @@
# Egress for Subscription Metrics and Operational Metadata
> **Important: Self Hosted Only**
> This section only applies to customers who are not running in offline mode and assumes you are using a self-hosted LangGraph Platform instance.
> This does not apply to SaaS or Hybrid deployments.
Self-Hosted LangGraph Platform instances store all information locally and will never send sensitive information outside of your network. We currently only track platform usage for billing purposes according to the entitlements in your order. In order to better remotely support our customers, we do require egress to `https://beacon.langchain.com`.
In the future, we will be introducing support diagnostics to help us ensure that the LangGraph Platform is running at an optimal level within your environment.
> **Warning**
> **This will require egress to `https://beacon.langchain.com` from your network.**
> **If using an API key, you will also need to allow egress to `https://api.smith.langchain.com` or `https://eu.api.smith.langchain.com` for API key verification.**
Generally, data that we send to Beacon can be categorized as follows:
- **Subscription Metrics**
- Subscription metrics are used to determine level of access and utilization of LangSmith. This includes, but are not limited to:
- Nodes Executed
- Runs Executed
- License Key Verification
- **Operational Metadata**
- This metadata will contain and collect the above subscription metrics to assist with remote support, allowing the LangChain team to diagnose and troubleshoot performance issues more effectively and proactively.
## Example Payloads
In an effort to maximize transparency, we provide sample payloads here:
### License Verification (If using an Enterprise License)
**Endpoint:**
`POST beacon.langchain.com/v1/beacon/verify`
**Request:**
```json
{
"license": "<YOUR_LICENSE_KEY>"
}
```
**Response:**
```json
{
"token": "Valid JWT" // Short-lived JWT token to avoid repeated license checks
}
```
### Api Key Verification (If using a LangSmith API Key)
**Endpoint:**
`POST api.smith.langchain.com/auth`
**Request:**
```json
"Headers": {
X-Api-Key: <YOUR_API_KEY>
}
```
**Response:**
```json
{
"org_config": {
"org_id": "3a1c2b6f-4430-4b92-8a5b-79b8b567bbc1",
... // Additional organization details
}
}
```
### Usage Reporting
**Endpoint:**
`POST beacon.langchain.com/v1/metadata/submit`
**Request:**
```json
{
"license": "<YOUR_LICENSE_KEY>",
"from_timestamp": "2025-01-06T09:00:00Z",
"to_timestamp": "2025-01-06T10:00:00Z",
"tags": {
"langgraph.python.version": "0.1.0",
"langgraph_api.version": "0.2.0",
"langgraph.platform.revision": "abc123",
"langgraph.platform.variant": "standard",
"langgraph.platform.host": "host-1",
"langgraph.platform.tenant_id": "3a1c2b6f-4430-4b92-8a5b-79b8b567bbc1",
"langgraph.platform.project_id": "c5b5f53a-4716-4326-8967-d4f7f7799735",
"langgraph.platform.plan": "enterprise",
"user_app.uses_indexing": "true",
"user_app.uses_custom_app": "false",
"user_app.uses_custom_auth": "true",
"user_app.uses_thread_ttl": "true",
"user_app.uses_store_ttl": "false"
},
"measures": {
"langgraph.platform.runs": 150,
"langgraph.platform.nodes": 450
},
"logs": []
}
```
**Response:**
```json
"204 No Content"
```
## Our Commitment
LangChain will not store any sensitive information in the Subscription Metrics or Operational Metadata. Any data collected will not be shared with a third party. If you have any concerns about the data being sent, please reach out to your account team.
+147
View File
@@ -0,0 +1,147 @@
# Rebuild Graph at Runtime
You might need to rebuild your graph with a different configuration for a new run. For example, you might need to use a different graph state or graph structure depending on the config. This guide shows how you can do this.
!!! note "Note"
In most cases, customizing behavior based on the config should be handled by a single graph where each node can read a config and change its behavior based on it
## Prerequisites
Make sure to check out [this how-to guide](./setup.md) on setting up your app for deployment first.
## Define graphs
Let's say you have an app with a simple graph that calls an LLM and returns the response to the user. The app file directory looks like the following:
```
my-app/
|-- requirements.txt
|-- .env
|-- openai_agent.py # code for your graph
```
where the graph is defined in `openai_agent.py`.
### No rebuild
In the standard LangGraph API configuration, the server uses the compiled graph instance that's defined at the top level of `openai_agent.py`, which looks like the following:
```python
from langchain_openai import ChatOpenAI
from langgraph.graph import END, START, MessageGraph
model = ChatOpenAI(temperature=0)
graph_workflow = MessageGraph()
graph_workflow.add_node("agent", model)
graph_workflow.add_edge("agent", END)
graph_workflow.add_edge(START, "agent")
agent = graph_workflow.compile()
```
To make the server aware of your graph, you need to specify a path to the variable that contains the `CompiledStateGraph` instance in your LangGraph API configuration (`langgraph.json`), e.g.:
```
{
"dependencies": ["."],
"graphs": {
"openai_agent": "./openai_agent.py:agent",
},
"env": "./.env"
}
```
### Rebuild
To make your graph rebuild on each new run with custom configuration, you need to rewrite `openai_agent.py` to instead provide a _function_ that takes a config and returns a graph (or compiled graph) instance. Let's say we want to return our existing graph for user ID '1', and a tool-calling agent for other users. We can modify `openai_agent.py` as follows:
```python
from typing import Annotated
from typing_extensions import TypedDict
from langchain_openai import ChatOpenAI
from langgraph.graph import END, START, MessageGraph
from langgraph.graph.state import StateGraph
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode
from langchain_core.tools import tool
from langchain_core.messages import BaseMessage
from langchain_core.runnables import RunnableConfig
class State(TypedDict):
messages: Annotated[list[BaseMessage], add_messages]
model = ChatOpenAI(temperature=0)
def make_default_graph():
"""Make a simple LLM agent"""
graph_workflow = StateGraph(State)
def call_model(state):
return {"messages": [model.invoke(state["messages"])]}
graph_workflow.add_node("agent", call_model)
graph_workflow.add_edge("agent", END)
graph_workflow.add_edge(START, "agent")
agent = graph_workflow.compile()
return agent
def make_alternative_graph():
"""Make a tool-calling agent"""
@tool
def add(a: float, b: float):
"""Adds two numbers."""
return a + b
tool_node = ToolNode([add])
model_with_tools = model.bind_tools([add])
def call_model(state):
return {"messages": [model_with_tools.invoke(state["messages"])]}
def should_continue(state: State):
if state["messages"][-1].tool_calls:
return "tools"
else:
return END
graph_workflow = StateGraph(State)
graph_workflow.add_node("agent", call_model)
graph_workflow.add_node("tools", tool_node)
graph_workflow.add_edge("tools", "agent")
graph_workflow.add_edge(START, "agent")
graph_workflow.add_conditional_edges("agent", should_continue)
agent = graph_workflow.compile()
return agent
# this is the graph making function that will decide which graph to
# build based on the provided config
def make_graph(config: RunnableConfig):
user_id = config.get("configurable", {}).get("user_id")
# route to different graph state / structure based on the user ID
if user_id == "1":
return make_default_graph()
else:
return make_alternative_graph()
```
Finally, you need to specify the path to your graph-making function (`make_graph`) in `langgraph.json`:
```
{
"dependencies": ["."],
"graphs": {
"openai_agent": "./openai_agent.py:make_graph",
},
"env": "./.env"
}
```
See more info on LangGraph API configuration file [here](../reference/cli.md#configuration-file)
Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 KiB

@@ -0,0 +1,53 @@
# How to Deploy Self-Hosted Control Plane
Before deploying, review the [conceptual guide for the Self-Hosted Control Plane](../../concepts/langgraph_self_hosted_control_plane.md) deployment option.
!!! info "Important"
The Self-Hosted Control Plane deployment option requires an [Enterprise](../../concepts/plans.md) plan.
## Prerequisites
1. You are using Kubernetes.
1. You have self-hosted LangSmith deployed.
1. Use the [LangGraph CLI](../../concepts/langgraph_cli.md) to [test your application locally](../../tutorials/langgraph-platform/local-server.md).
1. Use the [LangGraph CLI](../../concepts/langgraph_cli.md) to build a Docker image (i.e. `langgraph build`) and push it to a registry your Kubernetes cluster has access to.
1. `KEDA` is installed on your cluster.
helm repo add kedacore https://kedacore.github.io/charts
helm install keda kedacore/keda --namespace keda --create-namespace
1. Ingress Configuration
1. You must set up an ingress for your LangSmith instance. All agents will be deployed as Kubernetes services behind this ingress.
1. You can use this guide to [set up an ingress](https://docs.smith.langchain.com/self_hosting/configuration/ingress) for your instance.
1. You have slack space in your cluster for multiple deployments. `Cluster-Autoscaler` is recommended to automatically provision new nodes.
1. A valid Dynamic PV provisioner or PVs available on your cluster. You can verify this by running:
kubectl get storageclass
1. Egress to `https://beacon.langchain.com` from your network. This is required for license verification and usage reporting if not running in air-gapped mode. See the [Egress documentation](../../cloud/deployment/egress.md) for more details.
## Setup
1. As part of configuring your Self-Hosted LangSmith instance, you enable the `langgraphPlatform` option. This will provision a few key resources.
1. `listener`: This is a service that listens to the [control plane](../../concepts/langgraph_control_plane.md) for changes to your deployments and creates/updates downstream CRDs.
1. `LangGraphPlatform CRD`: A CRD for LangGraph Platform deployments. This contains the spec for managing an instance of a LangGraph platform deployment.
1. `operator`: This operator handles changes to your LangGraph Platform CRDs.
1. `host-backend`: This is the [control plane](../../concepts/langgraph_control_plane.md).
1. Two additional images will be used by the chart. Use the images that are specified in the latest release.
hostBackendImage:
repository: "docker.io/langchain/hosted-langserve-backend"
pullPolicy: IfNotPresent
operatorImage:
repository: "docker.io/langchain/langgraph-operator"
pullPolicy: IfNotPresent
1. In your config file for langsmith (usually `langsmith_config.yaml`, enable the `langgraphPlatform` option. Note that you must also have a valid ingress setup:
config:
langgraphPlatform:
enabled: true
langgraphPlatformLicenseKey: "YOUR_LANGGRAPH_PLATFORM_LICENSE_KEY"
1. In your `values.yaml` file, configure the `hostBackendImage` and `operatorImage` options (if you need to mirror images)
1. You can also configure base templates for your agents by overriding the base templates [here](https://github.com/langchain-ai/helm/blob/main/charts/langsmith/values.yaml#L898).
1. You create a deployment from the [control plane UI](../../concepts/langgraph_control_plane.md#control-plane-ui).
@@ -0,0 +1,59 @@
# How to Deploy Self-Hosted Data Plane
Before deploying, review the [conceptual guide for the Self-Hosted Data Plane](../../concepts/langgraph_self_hosted_data_plane.md) deployment option.
!!! info "Important"
The Self-Hosted Data Plane deployment option requires an [Enterprise](../../concepts/plans.md) plan.
## Prerequisites
1. Use the [LangGraph CLI](../../concepts/langgraph_cli.md) to [test your application locally](../../tutorials/langgraph-platform/local-server.md).
1. Use the [LangGraph CLI](../../concepts/langgraph_cli.md) to build a Docker image (i.e. `langgraph build`) and push it to a registry your Kubernetes cluster or Amazon ECS cluster has access to.
## Kubernetes
### Prerequisites
1. `KEDA` is installed on your cluster.
helm repo add kedacore https://kedacore.github.io/charts
helm install keda kedacore/keda --namespace keda --create-namespace
1. A valid `Ingress` controller is installed on your cluster.
1. You have slack space in your cluster for multiple deployments. `Cluster-Autoscaler` is recommended to automatically provision new nodes.
1. You will need to enable egress to two control plane URLs. The listener polls these endpoints for deployments:
https://api.host.langchain.com
https://api.smith.langchain.com
### Setup
1. You give us your LangSmith organization ID. We will enable the Self-Hosted Data Plane for your organization.
1. We provide you a [Helm chart](https://github.com/langchain-ai/helm/tree/main/charts/langgraph-dataplane) which you run to setup your Kubernetes cluster. This chart contains a few important components.
1. `langgraph-listener`: This is a service that listens to LangChain's [control plane](../../concepts/langgraph_control_plane.md) for changes to your deployments and creates/updates downstream CRDs.
1. `LangGraphPlatform CRD`: A CRD for LangGraph Platform deployments. This contains the spec for managing an instance of a LangGraph Platform deployment.
1. `langgraph-platform-operator`: This operator handles changes to your LangGraph Platform CRDs.
1. Configure your `langgraph-dataplane-values.yaml` file.
config:
langsmithApiKey: "" # API Key of your Workspace
langsmithWorkspaceId: "" # Workspace ID
hostBackendUrl: "https://api.host.langchain.com" # Only override this if on EU
smithBackendUrl: "https://api.smith.langchain.com" # Only override this if on EU
1. Deploy `langgraph-dataplane` Helm chart.
helm repo add langchain https://langchain-ai.github.io/helm/
helm repo update
helm upgrade -i langgraph-dataplane langchain/langgraph-dataplane --values langgraph-dataplane-values.yaml
1. If successful, you will see two services start up in your namespace.
NAME READY STATUS RESTARTS AGE
langgraph-dataplane-listener-7fccd788-wn2dx 0/1 Running 0 9s
langgraph-dataplane-redis-0 0/1 ContainerCreating 0 9s
1. You create a deployment from the [control plane UI](../../concepts/langgraph_control_plane.md#control-plane-ui).
## Amazon ECS
Coming soon!
@@ -0,0 +1,123 @@
# How to add semantic search to your LangGraph deployment
This guide explains how to add semantic search to your LangGraph deployment's cross-thread [store](../../concepts/persistence.md#memory-store), so that your agent can search for memories and other documents by semantic similarity.
## Prerequisites
- A LangGraph deployment (see [how to deploy](setup_pyproject.md))
- API keys for your embedding provider (in this case, OpenAI)
- `langchain >= 0.3.8` (if you specify using the string format below)
## Steps
1. Update your `langgraph.json` configuration file to include the store configuration:
```json
{
...
"store": {
"index": {
"embed": "openai:text-embedding-3-small",
"dims": 1536,
"fields": ["$"]
}
}
}
```
This configuration:
- Uses OpenAI's text-embedding-3-small model for generating embeddings
- Sets the embedding dimension to 1536 (matching the model's output)
- Indexes all fields in your stored data (`["$"]` means index everything, or specify specific fields like `["text", "metadata.title"]`)
2. To use the string embedding format above, make sure your dependencies include `langchain >= 0.3.8`:
```toml
# In pyproject.toml
[project]
dependencies = [
"langchain>=0.3.8"
]
```
Or if using requirements.txt:
```
langchain>=0.3.8
```
## Usage
Once configured, you can use semantic search in your LangGraph nodes. The store requires a namespace tuple to organize memories:
```python
def search_memory(state: State, *, store: BaseStore):
# Search the store using semantic similarity
# The namespace tuple helps organize different types of memories
# e.g., ("user_facts", "preferences") or ("conversation", "summaries")
results = store.search(
namespace=("memory", "facts"), # Organize memories by type
query="your search query",
limit=3 # number of results to return
)
return results
```
## Custom Embeddings
If you want to use custom embeddings, you can pass a path to a custom embedding function:
```json
{
...
"store": {
"index": {
"embed": "path/to/embedding_function.py:embed",
"dims": 1536,
"fields": ["$"]
}
}
}
```
The deployment will look for the function in the specified path. The function must be async and accept a list of strings:
```python
# path/to/embedding_function.py
from openai import AsyncOpenAI
client = AsyncOpenAI()
async def aembed_texts(texts: list[str]) -> list[list[float]]:
"""Custom embedding function that must:
1. Be async
2. Accept a list of strings
3. Return a list of float arrays (embeddings)
"""
response = await client.embeddings.create(
model="text-embedding-3-small",
input=texts
)
return [e.embedding for e in response.data]
```
## Querying via the API
You can also query the store using the LangGraph SDK. Since the SDK uses async operations:
```python
from langgraph_sdk import get_client
async def search_store():
client = get_client()
results = await client.store.search_items(
("memory", "facts"),
query="your search query",
limit=3 # number of results to return
)
return results
# Use in an async context
results = await search_store()
```
+188
View File
@@ -0,0 +1,188 @@
# How to Set Up a LangGraph Application with requirements.txt
A LangGraph application must be configured with a [LangGraph configuration file](../reference/cli.md#configuration-file) in order to be deployed to LangGraph Platform (or to be self-hosted). This how-to guide discusses the basic steps to setup a LangGraph application for deployment using `requirements.txt` to specify project dependencies.
This walkthrough is based on [this repository](https://github.com/langchain-ai/langgraph-example), which you can play around with to learn more about how to setup your LangGraph application for deployment.
!!! tip "Setup with pyproject.toml"
If you prefer using poetry for dependency management, check out [this how-to guide](./setup_pyproject.md) on using `pyproject.toml` for LangGraph Platform.
!!! tip "Setup with a Monorepo"
If you are interested in deploying a graph located inside a monorepo, take a look at [this repository](https://github.com/langchain-ai/langgraph-example-monorepo) for an example of how to do so.
The final repository structure will look something like this:
```bash
my-app/
├── my_agent # all project code lies within here
│ ├── utils # utilities for your graph
│ │ ├── __init__.py
│ │ ├── tools.py # tools for your graph
│ │ ├── nodes.py # node functions for you graph
│ │ └── state.py # state definition of your graph
│   ├── requirements.txt # package dependencies
│   ├── __init__.py
│   └── agent.py # code for constructing your graph
├── .env # environment variables
└── langgraph.json # configuration file for LangGraph
```
After each step, an example file directory is provided to demonstrate how code can be organized.
## Specify Dependencies
Dependencies can optionally be specified in one of the following files: `pyproject.toml`, `setup.py`, or `requirements.txt`. If none of these files is created, then dependencies can be specified later in the [LangGraph configuration file](#create-langgraph-configuration-file).
The dependencies below will be included in the image, you can also use them in your code, as long as with a compatible version range:
```
langgraph>=0.3.27
langgraph-sdk>=0.1.66
langgraph-checkpoint>=2.0.23
langchain-core>=0.2.38
langsmith>=0.1.63
orjson>=3.9.7,<3.10.17
httpx>=0.25.0
tenacity>=8.0.0
uvicorn>=0.26.0
sse-starlette>=2.1.0,<2.2.0
uvloop>=0.18.0
httptools>=0.5.0
jsonschema-rs>=0.20.0
structlog>=24.1.0
cloudpickle>=3.0.0
```
Example `requirements.txt` file:
```
langgraph
langchain_anthropic
tavily-python
langchain_community
langchain_openai
```
Example file directory:
```bash
my-app/
├── my_agent # all project code lies within here
│   └── requirements.txt # package dependencies
```
## Specify Environment Variables
Environment variables can optionally be specified in a file (e.g. `.env`). See the [Environment Variables reference](../reference/env_var.md) to configure additional variables for a deployment.
Example `.env` file:
```
MY_ENV_VAR_1=foo
MY_ENV_VAR_2=bar
OPENAI_API_KEY=key
```
Example file directory:
```bash
my-app/
├── my_agent # all project code lies within here
│   └── requirements.txt # package dependencies
└── .env # environment variables
```
## Define Graphs
Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each @[CompiledStateGraph][CompiledStateGraph] to be included in the LangGraph application. The variable names will be used later when creating the [LangGraph configuration file](../reference/cli.md#configuration-file).
Example `agent.py` file, which shows how to import from other modules you define (code for the modules is not shown here, please see [this repository](https://github.com/langchain-ai/langgraph-example) to see their implementation):
```python
# my_agent/agent.py
from typing import Literal
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, END, START
from my_agent.utils.nodes import call_model, should_continue, tool_node # import nodes
from my_agent.utils.state import AgentState # import state
# Define the runtime context
class GraphContext(TypedDict):
model_name: Literal["anthropic", "openai"]
workflow = StateGraph(AgentState, context_schema=GraphContext)
workflow.add_node("agent", call_model)
workflow.add_node("action", tool_node)
workflow.add_edge(START, "agent")
workflow.add_conditional_edges(
"agent",
should_continue,
{
"continue": "action",
"end": END,
},
)
workflow.add_edge("action", "agent")
graph = workflow.compile()
```
Example file directory:
```bash
my-app/
├── my_agent # all project code lies within here
│ ├── utils # utilities for your graph
│ │ ├── __init__.py
│ │ ├── tools.py # tools for your graph
│ │ ├── nodes.py # node functions for you graph
│ │ └── state.py # state definition of your graph
│   ├── requirements.txt # package dependencies
│   ├── __init__.py
│   └── agent.py # code for constructing your graph
└── .env # environment variables
```
## Create LangGraph Configuration File
Create a [LangGraph configuration file](../reference/cli.md#configuration-file) called `langgraph.json`. See the [LangGraph configuration file reference](../reference/cli.md#configuration-file) for detailed explanations of each key in the JSON object of the configuration file.
Example `langgraph.json` file:
```json
{
"dependencies": ["./my_agent"],
"graphs": {
"agent": "./my_agent/agent.py:graph"
},
"env": ".env"
}
```
Note that the variable name of the `CompiledGraph` appears at the end of the value of each subkey in the top-level `graphs` key (i.e. `:<variable_name>`).
!!! warning "Configuration File Location"
The LangGraph configuration file must be placed in a directory that is at the same level or higher than the Python files that contain compiled graphs and associated dependencies.
Example file directory:
```bash
my-app/
├── my_agent # all project code lies within here
│ ├── utils # utilities for your graph
│ │ ├── __init__.py
│ │ ├── tools.py # tools for your graph
│ │ ├── nodes.py # node functions for you graph
│ │ └── state.py # state definition of your graph
│   ├── requirements.txt # package dependencies
│   ├── __init__.py
│   └── agent.py # code for constructing your graph
├── .env # environment variables
└── langgraph.json # configuration file for LangGraph
```
## Next
After you setup your project and place it in a GitHub repository, it's time to [deploy your app](./cloud.md).
@@ -0,0 +1,199 @@
# How to Set Up a LangGraph.js Application
A [LangGraph.js](https://langchain-ai.github.io/langgraphjs/) application must be configured with a [LangGraph configuration file](../reference/cli.md#configuration-file) in order to be deployed to LangGraph Platform (or to be self-hosted). This how-to guide discusses the basic steps to setup a LangGraph.js application for deployment using `package.json` to specify project dependencies.
This walkthrough is based on [this repository](https://github.com/langchain-ai/langgraphjs-studio-starter), which you can play around with to learn more about how to setup your LangGraph application for deployment.
The final repository structure will look something like this:
```bash
my-app/
├── src # all project code lies within here
│ ├── utils # optional utilities for your graph
│ │ ├── tools.ts # tools for your graph
│ │ ├── nodes.ts # node functions for you graph
│ │ └── state.ts # state definition of your graph
│   └── agent.ts # code for constructing your graph
├── package.json # package dependencies
├── .env # environment variables
└── langgraph.json # configuration file for LangGraph
```
After each step, an example file directory is provided to demonstrate how code can be organized.
## Specify Dependencies
Dependencies can be specified in a `package.json`. If none of these files is created, then dependencies can be specified later in the [LangGraph configuration file](#create-langgraph-api-config).
Example `package.json` file:
```json
{
"name": "langgraphjs-studio-starter",
"packageManager": "yarn@1.22.22",
"dependencies": {
"@langchain/community": "^0.2.31",
"@langchain/core": "^0.2.31",
"@langchain/langgraph": "^0.2.0",
"@langchain/openai": "^0.2.8"
}
}
```
When deploying your app, the dependencies will be installed using the package manager of your choice, provided they adhere to the compatible version ranges listed below:
```
"@langchain/core": "^0.3.42",
"@langchain/langgraph": "^0.2.57",
"@langchain/langgraph-checkpoint": "~0.0.16",
```
Example file directory:
```bash
my-app/
└── package.json # package dependencies
```
## Specify Environment Variables
Environment variables can optionally be specified in a file (e.g. `.env`). See the [Environment Variables reference](../reference/env_var.md) to configure additional variables for a deployment.
Example `.env` file:
```
MY_ENV_VAR_1=foo
MY_ENV_VAR_2=bar
OPENAI_API_KEY=key
TAVILY_API_KEY=key_2
```
Example file directory:
```bash
my-app/
├── package.json
└── .env # environment variables
```
## Define Graphs
Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each compiled graph to be included in the LangGraph application. The variable names will be used later when creating the [LangGraph configuration file](../reference/cli.md#configuration-file).
Here is an example `agent.ts`:
```ts
import type { AIMessage } from "@langchain/core/messages";
import { TavilySearchResults } from "@langchain/community/tools/tavily_search";
import { ChatOpenAI } from "@langchain/openai";
import { MessagesAnnotation, StateGraph } from "@langchain/langgraph";
import { ToolNode } from "@langchain/langgraph/prebuilt";
const tools = [new TavilySearchResults({ maxResults: 3 })];
// Define the function that calls the model
async function callModel(state: typeof MessagesAnnotation.State) {
/**
* Call the LLM powering our agent.
* Feel free to customize the prompt, model, and other logic!
*/
const model = new ChatOpenAI({
model: "gpt-4o",
}).bindTools(tools);
const response = await model.invoke([
{
role: "system",
content: `You are a helpful assistant. The current date is ${new Date().getTime()}.`,
},
...state.messages,
]);
// MessagesAnnotation supports returning a single message or array of messages
return { messages: response };
}
// Define the function that determines whether to continue or not
function routeModelOutput(state: typeof MessagesAnnotation.State) {
const messages = state.messages;
const lastMessage: AIMessage = messages[messages.length - 1];
// If the LLM is invoking tools, route there.
if ((lastMessage?.tool_calls?.length ?? 0) > 0) {
return "tools";
}
// Otherwise end the graph.
return "__end__";
}
// Define a new graph.
// See https://langchain-ai.github.io/langgraphjs/how-tos/define-state/#getting-started for
// more on defining custom graph states.
const workflow = new StateGraph(MessagesAnnotation)
// Define the two nodes we will cycle between
.addNode("callModel", callModel)
.addNode("tools", new ToolNode(tools))
// Set the entrypoint as `callModel`
// This means that this node is the first one called
.addEdge("__start__", "callModel")
.addConditionalEdges(
// First, we define the edges' source node. We use `callModel`.
// This means these are the edges taken after the `callModel` node is called.
"callModel",
// Next, we pass in the function that will determine the sink node(s), which
// will be called after the source node is called.
routeModelOutput,
// List of the possible destinations the conditional edge can route to.
// Required for conditional edges to properly render the graph in Studio
["tools", "__end__"]
)
// This means that after `tools` is called, `callModel` node is called next.
.addEdge("tools", "callModel");
// Finally, we compile it!
// This compiles it into a graph you can invoke and deploy.
export const graph = workflow.compile();
```
Example file directory:
```bash
my-app/
├── src # all project code lies within here
│ ├── utils # optional utilities for your graph
│ │ ├── tools.ts # tools for your graph
│ │ ├── nodes.ts # node functions for you graph
│ │ └── state.ts # state definition of your graph
│   └── agent.ts # code for constructing your graph
├── package.json # package dependencies
├── .env # environment variables
└── langgraph.json # configuration file for LangGraph
```
## Create LangGraph API Config
Create a [LangGraph configuration file](../reference/cli.md#configuration-file) called `langgraph.json`. See the [LangGraph configuration file reference](../reference/cli.md#configuration-file) for detailed explanations of each key in the JSON object of the configuration file.
Example `langgraph.json` file:
```json
{
"node_version": "20",
"dockerfile_lines": [],
"dependencies": ["."],
"graphs": {
"agent": "./src/agent.ts:graph"
},
"env": ".env"
}
```
Note that the variable name of the `CompiledGraph` appears at the end of the value of each subkey in the top-level `graphs` key (i.e. `:<variable_name>`).
!!! info "Configuration Location"
The LangGraph configuration file must be placed in a directory that is at the same level or higher than the TypeScript files that contain compiled graphs and associated dependencies.
## Next
After you setup your project and place it in a GitHub repository, it's time to [deploy your app](./cloud.md).
@@ -0,0 +1,201 @@
# How to Set Up a LangGraph Application with pyproject.toml
A LangGraph application must be configured with a [LangGraph configuration file](../reference/cli.md#configuration-file) in order to be deployed to LangGraph Platform (or to be self-hosted). This how-to guide discusses the basic steps to setup a LangGraph application for deployment using `pyproject.toml` to define your package's dependencies.
This walkthrough is based on [this repository](https://github.com/langchain-ai/langgraph-example-pyproject), which you can play around with to learn more about how to setup your LangGraph application for deployment.
!!! tip "Setup with requirements.txt"
If you prefer using `requirements.txt` for dependency management, check out [this how-to guide](./setup.md).
!!! tip "Setup with a Monorepo"
If you are interested in deploying a graph located inside a monorepo, take a look at [this](https://github.com/langchain-ai/langgraph-example-monorepo) repository for an example of how to do so.
The final repository structure will look something like this:
```bash
my-app/
├── my_agent # all project code lies within here
│ ├── utils # utilities for your graph
│ │ ├── __init__.py
│ │ ├── tools.py # tools for your graph
│ │ ├── nodes.py # node functions for you graph
│ │ └── state.py # state definition of your graph
│   ├── __init__.py
│   └── agent.py # code for constructing your graph
├── .env # environment variables
├── langgraph.json # configuration file for LangGraph
└── pyproject.toml # dependencies for your project
```
After each step, an example file directory is provided to demonstrate how code can be organized.
## Specify Dependencies
Dependencies can optionally be specified in one of the following files: `pyproject.toml`, `setup.py`, or `requirements.txt`. If none of these files is created, then dependencies can be specified later in the [LangGraph configuration file](#create-langgraph-configuration-file).
The dependencies below will be included in the image, you can also use them in your code, as long as with a compatible version range:
```
langgraph>=0.3.27
langgraph-sdk>=0.1.66
langgraph-checkpoint>=2.0.23
langchain-core>=0.2.38
langsmith>=0.1.63
orjson>=3.9.7,<3.10.17
httpx>=0.25.0
tenacity>=8.0.0
uvicorn>=0.26.0
sse-starlette>=2.1.0,<2.2.0
uvloop>=0.18.0
httptools>=0.5.0
jsonschema-rs>=0.20.0
structlog>=24.1.0
cloudpickle>=3.0.0
```
Example `pyproject.toml` file:
```toml
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "my-agent"
version = "0.0.1"
description = "An excellent agent build for LangGraph Platform."
authors = [
{name = "Polly the parrot", email = "1223+polly@users.noreply.github.com"}
]
license = {text = "MIT"}
readme = "README.md"
requires-python = ">=3.9"
dependencies = [
"langgraph>=0.2.0",
"langchain-fireworks>=0.1.3"
]
[tool.hatch.build.targets.wheel]
packages = ["my_agent"]
```
Example file directory:
```bash
my-app/
└── pyproject.toml # Python packages required for your graph
```
## Specify Environment Variables
Environment variables can optionally be specified in a file (e.g. `.env`). See the [Environment Variables reference](../reference/env_var.md) to configure additional variables for a deployment.
Example `.env` file:
```
MY_ENV_VAR_1=foo
MY_ENV_VAR_2=bar
FIREWORKS_API_KEY=key
```
Example file directory:
```bash
my-app/
├── .env # file with environment variables
└── pyproject.toml
```
## Define Graphs
Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each @[CompiledStateGraph][CompiledStateGraph] to be included in the LangGraph application. The variable names will be used later when creating the [LangGraph configuration file](../reference/cli.md#configuration-file).
Example `agent.py` file, which shows how to import from other modules you define (code for the modules is not shown here, please see [this repository](https://github.com/langchain-ai/langgraph-example-pyproject) to see their implementation):
```python
# my_agent/agent.py
from typing import Literal
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, END, START
from my_agent.utils.nodes import call_model, should_continue, tool_node # import nodes
from my_agent.utils.state import AgentState # import state
# Define the runtime context
class GraphContext(TypedDict):
model_name: Literal["anthropic", "openai"]
workflow = StateGraph(AgentState, context_schema=GraphContext)
workflow.add_node("agent", call_model)
workflow.add_node("action", tool_node)
workflow.add_edge(START, "agent")
workflow.add_conditional_edges(
"agent",
should_continue,
{
"continue": "action",
"end": END,
},
)
workflow.add_edge("action", "agent")
graph = workflow.compile()
```
Example file directory:
```bash
my-app/
├── my_agent # all project code lies within here
│ ├── utils # utilities for your graph
│ │ ├── __init__.py
│ │ ├── tools.py # tools for your graph
│ │ ├── nodes.py # node functions for you graph
│ │ └── state.py # state definition of your graph
│   ├── __init__.py
│   └── agent.py # code for constructing your graph
├── .env
└── pyproject.toml
```
## Create LangGraph Configuration File
Create a [LangGraph configuration file](../reference/cli.md#configuration-file) called `langgraph.json`. See the [LangGraph configuration file reference](../reference/cli.md#configuration-file) for detailed explanations of each key in the JSON object of the configuration file.
Example `langgraph.json` file:
```json
{
"dependencies": ["."],
"graphs": {
"agent": "./my_agent/agent.py:graph"
},
"env": ".env"
}
```
Note that the variable name of the `CompiledGraph` appears at the end of the value of each subkey in the top-level `graphs` key (i.e. `:<variable_name>`).
!!! warning "Configuration File Location"
The LangGraph configuration file must be placed in a directory that is at the same level or higher than the Python files that contain compiled graphs and associated dependencies.
Example file directory:
```bash
my-app/
├── my_agent # all project code lies within here
│ ├── utils # utilities for your graph
│ │ ├── __init__.py
│ │ ├── tools.py # tools for your graph
│ │ ├── nodes.py # node functions for you graph
│ │ └── state.py # state definition of your graph
│   ├── __init__.py
│   └── agent.py # code for constructing your graph
├── .env # environment variables
├── langgraph.json # configuration file for LangGraph
└── pyproject.toml # dependencies for your project
```
## Next
After you setup your project and place it in a GitHub repository, it's time to [deploy your app](./cloud.md).
@@ -0,0 +1,110 @@
# How to Deploy a Standalone Container
Before deploying, review the [conceptual guide for the Standalone Container](../../concepts/langgraph_standalone_container.md) deployment option.
## Prerequisites
1. Use the [LangGraph CLI](../../concepts/langgraph_cli.md) to [test your application locally](../../tutorials/langgraph-platform/local-server.md).
1. Use the [LangGraph CLI](../../concepts/langgraph_cli.md) to build a Docker image (i.e. `langgraph build`).
1. The following environment variables are needed for a standalone container deployment.
1. `REDIS_URI`: Connection details to a Redis instance. Redis will be used as a pub-sub broker to enable streaming real time output from background runs. The value of `REDIS_URI` must be a valid [Redis connection URI](https://redis-py.readthedocs.io/en/stable/connections.html#redis.Redis.from_url).
!!! Note "Shared Redis Instance"
Multiple self-hosted deployments can share the same Redis instance. For example, for `Deployment A`, `REDIS_URI` can be set to `redis://<hostname_1>:<port>/1` and for `Deployment B`, `REDIS_URI` can be set to `redis://<hostname_1>:<port>/2`.
`1` and `2` are different database numbers within the same instance, but `<hostname_1>` is shared. **The same database number cannot be used for separate deployments**.
1. `DATABASE_URI`: Postgres connection details. Postgres will be used to store assistants, threads, runs, persist thread state and long term memory, and to manage the state of the background task queue with 'exactly once' semantics. The value of `DATABASE_URI` must be a valid [Postgres connection URI](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING-URIS).
!!! Note "Shared Postgres Instance"
Multiple self-hosted deployments can share the same Postgres instance. For example, for `Deployment A`, `DATABASE_URI` can be set to `postgres://<user>:<password>@/<database_name_1>?host=<hostname_1>` and for `Deployment B`, `DATABASE_URI` can be set to `postgres://<user>:<password>@/<database_name_2>?host=<hostname_1>`.
`<database_name_1>` and `database_name_2` are different databases within the same instance, but `<hostname_1>` is shared. **The same database cannot be used for separate deployments**.
1. `LANGGRAPH_CLOUD_LICENSE_KEY`: (if using [Enterprise](../../concepts/langgraph_data_plane.md#licensing)) LangGraph Platform license key. This will be used to authenticate ONCE at server start up.
1. `LANGSMITH_ENDPOINT`: To send traces to a [self-hosted LangSmith](https://docs.smith.langchain.com/self_hosting) instance, set `LANGSMITH_ENDPOINT` to the hostname of the self-hosted LangSmith instance.
1. Egress to `https://beacon.langchain.com` from your network. This is required for license verification and usage reporting if not running in air-gapped mode. See the [Egress documentation](../../cloud/deployment/egress.md) for more details.
## Kubernetes (Helm)
Use this [Helm chart](https://github.com/langchain-ai/helm/blob/main/charts/langgraph-cloud/README.md) to deploy a LangGraph Server to a Kubernetes cluster.
## Docker
Run the following `docker` command:
```shell
docker run \
--env-file .env \
-p 8123:8000 \
-e REDIS_URI="foo" \
-e DATABASE_URI="bar" \
-e LANGSMITH_API_KEY="baz" \
my-image
```
!!! note
* You need to replace `my-image` with the name of the image you built in the prerequisite steps (from `langgraph build`)
and you should provide appropriate values for `REDIS_URI`, `DATABASE_URI`, and `LANGSMITH_API_KEY`.
* If your application requires additional environment variables, you can pass them in a similar way.
## Docker Compose
Docker Compose YAML file:
```yml
volumes:
langgraph-data:
driver: local
services:
langgraph-redis:
image: redis:6
healthcheck:
test: redis-cli ping
interval: 5s
timeout: 1s
retries: 5
langgraph-postgres:
image: postgres:16
ports:
- "5433:5432"
environment:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
volumes:
- langgraph-data:/var/lib/postgresql/data
healthcheck:
test: pg_isready -U postgres
start_period: 10s
timeout: 1s
retries: 5
interval: 5s
langgraph-api:
image: ${IMAGE_NAME}
ports:
- "8123:8000"
depends_on:
langgraph-redis:
condition: service_healthy
langgraph-postgres:
condition: service_healthy
env_file:
- .env
environment:
REDIS_URI: redis://langgraph-redis:6379
LANGSMITH_API_KEY: ${LANGSMITH_API_KEY}
POSTGRES_URI: postgres://postgres:postgres@langgraph-postgres:5432/postgres?sslmode=disable
```
You can run the command `docker compose up` with this Docker Compose file in the same folder.
This will launch a LangGraph Server on port `8123` (if you want to change this, you can change this by changing the ports in the `langgraph-api` volume). You can test if the application is healthy by running:
```shell
curl --request GET --url 0.0.0.0:8123/ok
```
Assuming everything is running correctly, you should see a response like:
```shell
{"ok":true}
```
@@ -0,0 +1,486 @@
# Human-in-the-loop using Server API
To review, edit, and approve tool calls in an agent or workflow, use LangGraph's [human-in-the-loop](../../concepts/human_in_the_loop.md) features.
## Dynamic interrupts
=== "Python"
```python
from langgraph_sdk import get_client
# highlight-next-line
from langgraph_sdk.schema import Command
client = get_client(url=<DEPLOYMENT_URL>)
# Using the graph deployed with the name "agent"
assistant_id = "agent"
# create a thread
thread = await client.threads.create()
thread_id = thread["thread_id"]
# Run the graph until the interrupt is hit.
result = await client.runs.wait(
thread_id,
assistant_id,
input={"some_text": "original text"} # (1)!
)
print(result['__interrupt__']) # (2)!
# > [
# > {
# > 'value': {'text_to_revise': 'original text'},
# > 'id': '...',
# > }
# > ]
# Resume the graph
print(await client.runs.wait(
thread_id,
assistant_id,
# highlight-next-line
command=Command(resume="Edited text") # (3)!
))
# > {'some_text': 'Edited text'}
```
1. The graph is invoked with some initial state.
2. When the graph hits the interrupt, it returns an interrupt object with the payload and metadata.
3. The graph is resumed with a `Command(resume=...)`, injecting the human's input and continuing execution.
=== "JavaScript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });
// Using the graph deployed with the name "agent"
const assistantID = "agent";
// create a thread
const thread = await client.threads.create();
const threadID = thread["thread_id"];
// Run the graph until the interrupt is hit.
const result = await client.runs.wait(
threadID,
assistantID,
{ input: { "some_text": "original text" } } // (1)!
);
console.log(result['__interrupt__']); // (2)!
// > [
// > {
// > 'value': {'text_to_revise': 'original text'},
// > 'resumable': True,
// > 'ns': ['human_node:fc722478-2f21-0578-c572-d9fc4dd07c3b'],
// > 'when': 'during'
// > }
// > ]
// Resume the graph
console.log(await client.runs.wait(
threadID,
assistantID,
// highlight-next-line
{ command: { resume: "Edited text" }} // (3)!
));
// > {'some_text': 'Edited text'}
```
1. The graph is invoked with some initial state.
2. When the graph hits the interrupt, it returns an interrupt object with the payload and metadata.
3. The graph is resumed with a `{ resume: ... }` command object, injecting the human's input and continuing execution.
=== "cURL"
Create a thread:
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}'
```
Run the graph until the interrupt is hit.:
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/wait \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {\"some_text\": \"original text\"}
}"
```
Resume the graph:
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/wait \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"command\": {
\"resume\": \"Edited text\"
}
}"
```
??? example "Extended example: using `interrupt`"
This is an example graph you can run in the LangGraph API server.
See [LangGraph Platform quickstart](../quick_start.md) for more details.
```python
from typing import TypedDict
import uuid
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.constants import START
from langgraph.graph import StateGraph
# highlight-next-line
from langgraph.types import interrupt, Command
class State(TypedDict):
some_text: str
def human_node(state: State):
# highlight-next-line
value = interrupt( # (1)!
{
"text_to_revise": state["some_text"] # (2)!
}
)
return {
"some_text": value # (3)!
}
# Build the graph
graph_builder = StateGraph(State)
graph_builder.add_node("human_node", human_node)
graph_builder.add_edge(START, "human_node")
graph = graph_builder.compile()
```
1. `interrupt(...)` pauses execution at `human_node`, surfacing the given payload to a human.
2. Any JSON serializable value can be passed to the `interrupt` function. Here, a dict containing the text to revise.
3. Once resumed, the return value of `interrupt(...)` is the human-provided input, which is used to update the state.
Once you have a running LangGraph API server, you can interact with it using
[LangGraph SDK](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/)
=== "Python"
```python
from langgraph_sdk import get_client
# highlight-next-line
from langgraph_sdk.schema import Command
client = get_client(url=<DEPLOYMENT_URL>)
# Using the graph deployed with the name "agent"
assistant_id = "agent"
# create a thread
thread = await client.threads.create()
thread_id = thread["thread_id"]
# Run the graph until the interrupt is hit.
result = await client.runs.wait(
thread_id,
assistant_id,
input={"some_text": "original text"} # (1)!
)
print(result['__interrupt__']) # (2)!
# > [
# > {
# > 'value': {'text_to_revise': 'original text'},
# > 'id': '...',
# > }
# > ]
# Resume the graph
print(await client.runs.wait(
thread_id,
assistant_id,
# highlight-next-line
command=Command(resume="Edited text") # (3)!
))
# > {'some_text': 'Edited text'}
```
1. The graph is invoked with some initial state.
2. When the graph hits the interrupt, it returns an interrupt object with the payload and metadata.
3. The graph is resumed with a `Command(resume=...)`, injecting the human's input and continuing execution.
=== "JavaScript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });
// Using the graph deployed with the name "agent"
const assistantID = "agent";
// create a thread
const thread = await client.threads.create();
const threadID = thread["thread_id"];
// Run the graph until the interrupt is hit.
const result = await client.runs.wait(
threadID,
assistantID,
{ input: { "some_text": "original text" } } // (1)!
);
console.log(result['__interrupt__']); // (2)!
// > [
// > {
// > 'value': {'text_to_revise': 'original text'},
// > 'resumable': True,
// > 'ns': ['human_node:fc722478-2f21-0578-c572-d9fc4dd07c3b'],
// > 'when': 'during'
// > }
// > ]
// Resume the graph
console.log(await client.runs.wait(
threadID,
assistantID,
// highlight-next-line
{ command: { resume: "Edited text" }} // (3)!
));
// > {'some_text': 'Edited text'}
```
1. The graph is invoked with some initial state.
2. When the graph hits the interrupt, it returns an interrupt object with the payload and metadata.
3. The graph is resumed with a `{ resume: ... }` command object, injecting the human's input and continuing execution.
=== "cURL"
Create a thread:
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}'
```
Run the graph until the interrupt is hit:
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/wait \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {\"some_text\": \"original text\"}
}"
```
Resume the graph:
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/wait \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"command\": {
\"resume\": \"Edited text\"
}
}"
```
## Static interrupts
Static interrupts (also known as static breakpoints) are triggered either before or after a node executes.
!!! warning
Static interrupts are **not** recommended for human-in-the-loop workflows. They are best used for debugging and testing.
You can set static interrupts by specifying `interrupt_before` and `interrupt_after` at compile time:
```python
# highlight-next-line
graph = graph_builder.compile( # (1)!
# highlight-next-line
interrupt_before=["node_a"], # (2)!
# highlight-next-line
interrupt_after=["node_b", "node_c"], # (3)!
)
```
1. The breakpoints are set during `compile` time.
2. `interrupt_before` specifies the nodes where execution should pause before the node is executed.
3. `interrupt_after` specifies the nodes where execution should pause after the node is executed.
Alternatively, you can set static interrupts at run time:
=== "Python"
```python
# highlight-next-line
await client.runs.wait( # (1)!
thread_id,
assistant_id,
inputs=inputs,
# highlight-next-line
interrupt_before=["node_a"], # (2)!
# highlight-next-line
interrupt_after=["node_b", "node_c"] # (3)!
)
```
1. `client.runs.wait` is called with the `interrupt_before` and `interrupt_after` parameters. This is a run-time configuration and can be changed for every invocation.
2. `interrupt_before` specifies the nodes where execution should pause before the node is executed.
3. `interrupt_after` specifies the nodes where execution should pause after the node is executed.
=== "JavaScript"
```js
// highlight-next-line
await client.runs.wait( // (1)!
threadID,
assistantID,
{
input: input,
// highlight-next-line
interruptBefore: ["node_a"], // (2)!
// highlight-next-line
interruptAfter: ["node_b", "node_c"] // (3)!
}
)
```
1. `client.runs.wait` is called with the `interruptBefore` and `interruptAfter` parameters. This is a run-time configuration and can be changed for every invocation.
2. `interruptBefore` specifies the nodes where execution should pause before the node is executed.
3. `interruptAfter` specifies the nodes where execution should pause after the node is executed.
=== "cURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/wait \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"interrupt_before\": [\"node_a\"],
\"interrupt_after\": [\"node_b\", \"node_c\"],
\"input\": <INPUT>
}"
```
The following example shows how to add static interrupts:
=== "Python"
```python
from langgraph_sdk import get_client
client = get_client(url=<DEPLOYMENT_URL>)
# Using the graph deployed with the name "agent"
assistant_id = "agent"
# create a thread
thread = await client.threads.create()
thread_id = thread["thread_id"]
# Run the graph until the breakpoint
result = await client.runs.wait(
thread_id,
assistant_id,
input=inputs # (1)!
)
# Resume the graph
await client.runs.wait(
thread_id,
assistant_id,
input=None # (2)!
)
```
1. The graph is run until the first breakpoint is hit.
2. The graph is resumed by passing in `None` for the input. This will run the graph until the next breakpoint is hit.
=== "JavaScript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });
// Using the graph deployed with the name "agent"
const assistantID = "agent";
// create a thread
const thread = await client.threads.create();
const threadID = thread["thread_id"];
// Run the graph until the breakpoint
const result = await client.runs.wait(
threadID,
assistantID,
{ input: input } // (1)!
);
// Resume the graph
await client.runs.wait(
threadID,
assistantID,
{ input: null } // (2)!
);
```
1. The graph is run until the first breakpoint is hit.
2. The graph is resumed by passing in `null` for the input. This will run the graph until the next breakpoint is hit.
=== "cURL"
Create a thread:
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}'
```
Run the graph until the breakpoint:
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/wait \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": <INPUT>
}"
```
Resume the graph:
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/wait \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\"
}"
```
## Learn more
- [Human-in-the-loop conceptual guide](../../concepts/human_in_the_loop.md): learn more about LangGraph human-in-the-loop features.
- [Common patterns](../../how-tos/human_in_the_loop/add-human-in-the-loop.md#common-patterns): learn how to implement patterns like approving/rejecting actions, requesting user input, tool call review, and validating human input.
+451
View File
@@ -0,0 +1,451 @@
# How to kick off background runs
This guide covers how to kick off background runs for your agent.
This can be useful for long running jobs.
## Setup
First let's set up our client and thread:
=== "Python"
```python
from langgraph_sdk import get_client
client = get_client(url=<DEPLOYMENT_URL>)
# Using the graph deployed with the name "agent"
assistant_id = "agent"
# create thread
thread = await client.threads.create()
print(thread)
```
=== "Javascript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });
// Using the graph deployed with the name "agent"
const assistantID = "agent";
// create thread
const thread = await client.threads.create();
console.log(thread);
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}'
```
Output:
{
'thread_id': '5cb1e8a1-34b3-4a61-a34e-71a9799bd00d',
'created_at': '2024-08-30T20:35:52.062934+00:00',
'updated_at': '2024-08-30T20:35:52.062934+00:00',
'metadata': {},
'status': 'idle',
'config': {},
'values': None
}
## Check runs on thread
If we list the current runs on this thread, we will see that it's empty:
=== "Python"
```python
runs = await client.runs.list(thread["thread_id"])
print(runs)
```
=== "Javascript"
```js
let runs = await client.runs.list(thread['thread_id']);
console.log(runs);
```
=== "CURL"
```bash
curl --request GET \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs
```
Output:
[]
## Start runs on thread
Now let's kick off a run:
=== "Python"
```python
input = {"messages": [{"role": "user", "content": "what's the weather in sf"}]}
run = await client.runs.create(thread["thread_id"], assistant_id, input=input)
```
=== "Javascript"
```js
let input = {"messages": [{"role": "user", "content": "what's the weather in sf"}]};
let run = await client.runs.create(thread["thread_id"], assistantID, { input });
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs \
--header 'Content-Type: application/json' \
--data '{
"assistant_id": <ASSISTANT_ID>
}'
```
The first time we poll it, we can see `status=pending`:
=== "Python"
```python
print(await client.runs.get(thread["thread_id"], run["run_id"]))
```
=== "Javascript"
```js
console.log(await client.runs.get(thread["thread_id"], run["run_id"]));
```
=== "CURL"
```bash
curl --request GET \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/<RUN_ID>
```
Output:
{
"run_id": "1ef6a5f8-bd86-6763-bbd6-bff042db7b1b",
"thread_id": "7885f0cf-94ad-4040-91d7-73f7ba007c8a",
"assistant_id": "fe096781-5601-53d2-b2f6-0d3403f7e9ca",
"created_at": "2024-09-04T01:46:47.244887+00:00",
"updated_at": "2024-09-04T01:46:47.244887+00:00",
"metadata": {},
"status": "pending",
"kwargs": {
"input": {
"messages": [
{
"role": "user",
"content": "what's the weather in sf"
}
]
},
"config": {
"metadata": {
"created_by": "system"
},
"configurable": {
"run_id": "1ef6a5f8-bd86-6763-bbd6-bff042db7b1b",
"user_id": "",
"graph_id": "agent",
"thread_id": "7885f0cf-94ad-4040-91d7-73f7ba007c8a",
"assistant_id": "fe096781-5601-53d2-b2f6-0d3403f7e9ca",
"checkpoint_id": null
}
},
"webhook": null,
"temporary": false,
"stream_mode": [
"values"
],
"feedback_keys": null,
"interrupt_after": null,
"interrupt_before": null
},
"multitask_strategy": "reject"
}
Now we can join the run, wait for it to finish and check that status again:
=== "Python"
```python
await client.runs.join(thread["thread_id"], run["run_id"])
print(await client.runs.get(thread["thread_id"], run["run_id"]))
```
=== "Javascript"
```js
await client.runs.join(thread["thread_id"], run["run_id"]);
console.log(await client.runs.get(thread["thread_id"], run["run_id"]));
```
=== "CURL"
```bash
curl --request GET \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/<RUN_ID>/join &&
curl --request GET \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/<RUN_ID>
```
Output:
{
"run_id": "1ef6a5f8-bd86-6763-bbd6-bff042db7b1b",
"thread_id": "7885f0cf-94ad-4040-91d7-73f7ba007c8a",
"assistant_id": "fe096781-5601-53d2-b2f6-0d3403f7e9ca",
"created_at": "2024-09-04T01:46:47.244887+00:00",
"updated_at": "2024-09-04T01:46:47.244887+00:00",
"metadata": {},
"status": "success",
"kwargs": {
"input": {
"messages": [
{
"role": "user",
"content": "what's the weather in sf"
}
]
},
"config": {
"metadata": {
"created_by": "system"
},
"configurable": {
"run_id": "1ef6a5f8-bd86-6763-bbd6-bff042db7b1b",
"user_id": "",
"graph_id": "agent",
"thread_id": "7885f0cf-94ad-4040-91d7-73f7ba007c8a",
"assistant_id": "fe096781-5601-53d2-b2f6-0d3403f7e9ca",
"checkpoint_id": null
}
},
"webhook": null,
"temporary": false,
"stream_mode": [
"values"
],
"feedback_keys": null,
"interrupt_after": null,
"interrupt_before": null
},
"multitask_strategy": "reject"
}
Perfect! The run succeeded as we would expect. We can double check that the run worked as expected by printing out the final state:
=== "Python"
```python
final_result = await client.threads.get_state(thread["thread_id"])
print(final_result)
```
=== "Javascript"
```js
let finalResult = await client.threads.getState(thread["thread_id"]);
console.log(finalResult);
```
=== "CURL"
```bash
curl --request GET \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/state
```
Output:
{
"values": {
"messages": [
{
"content": "what's the weather in sf",
"additional_kwargs": {},
"response_metadata": {},
"type": "human",
"name": null,
"id": "beba31bf-320d-4125-9c37-cadf526ac47a",
"example": false
},
{
"content": [
{
"id": "toolu_01AaNPSPzqia21v7aAKwbKYm",
"input": {},
"name": "tavily_search_results_json",
"type": "tool_use",
"index": 0,
"partial_json": "{\"query\": \"weather in san francisco\"}"
}
],
"additional_kwargs": {},
"response_metadata": {
"stop_reason": "tool_use",
"stop_sequence": null
},
"type": "ai",
"name": null,
"id": "run-f220faf8-1d27-4f73-ad91-6bb3f47e8639",
"example": false,
"tool_calls": [
{
"name": "tavily_search_results_json",
"args": {
"query": "weather in san francisco"
},
"id": "toolu_01AaNPSPzqia21v7aAKwbKYm",
"type": "tool_call"
}
],
"invalid_tool_calls": [],
"usage_metadata": {
"input_tokens": 273,
"output_tokens": 61,
"total_tokens": 334
}
},
{
"content": "[{\"url\": \"https://www.weatherapi.com/\", \"content\": \"{'location': {'name': 'San Francisco', 'region': 'California', 'country': 'United States of America', 'lat': 37.78, 'lon': -122.42, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1725052131, 'localtime': '2024-08-30 14:08'}, 'current': {'last_updated_epoch': 1725051600, 'last_updated': '2024-08-30 14:00', 'temp_c': 21.1, 'temp_f': 70.0, 'is_day': 1, 'condition': {'text': 'Partly cloudy', 'icon': '//cdn.weatherapi.com/weather/64x64/day/116.png', 'code': 1003}, 'wind_mph': 11.9, 'wind_kph': 19.1, 'wind_degree': 290, 'wind_dir': 'WNW', 'pressure_mb': 1018.0, 'pressure_in': 30.07, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 59, 'cloud': 25, 'feelslike_c': 21.1, 'feelslike_f': 70.0, 'windchill_c': 18.6, 'windchill_f': 65.5, 'heatindex_c': 18.6, 'heatindex_f': 65.5, 'dewpoint_c': 12.2, 'dewpoint_f': 54.0, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 5.0, 'gust_mph': 15.0, 'gust_kph': 24.2}}\"}]",
"additional_kwargs": {},
"response_metadata": {},
"type": "tool",
"name": "tavily_search_results_json",
"id": "686b2487-f332-4e58-9508-89b3a814cd81",
"tool_call_id": "toolu_01AaNPSPzqia21v7aAKwbKYm",
"artifact": {
"query": "weather in san francisco",
"follow_up_questions": null,
"answer": null,
"images": [],
"results": [
{
"title": "Weather in San Francisco",
"url": "https://www.weatherapi.com/",
"content": "{'location': {'name': 'San Francisco', 'region': 'California', 'country': 'United States of America', 'lat': 37.78, 'lon': -122.42, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1725052131, 'localtime': '2024-08-30 14:08'}, 'current': {'last_updated_epoch': 1725051600, 'last_updated': '2024-08-30 14:00', 'temp_c': 21.1, 'temp_f': 70.0, 'is_day': 1, 'condition': {'text': 'Partly cloudy', 'icon': '//cdn.weatherapi.com/weather/64x64/day/116.png', 'code': 1003}, 'wind_mph': 11.9, 'wind_kph': 19.1, 'wind_degree': 290, 'wind_dir': 'WNW', 'pressure_mb': 1018.0, 'pressure_in': 30.07, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 59, 'cloud': 25, 'feelslike_c': 21.1, 'feelslike_f': 70.0, 'windchill_c': 18.6, 'windchill_f': 65.5, 'heatindex_c': 18.6, 'heatindex_f': 65.5, 'dewpoint_c': 12.2, 'dewpoint_f': 54.0, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 5.0, 'gust_mph': 15.0, 'gust_kph': 24.2}}",
"score": 0.976148,
"raw_content": null
}
],
"response_time": 3.07
},
"status": "success"
},
{
"content": [
{
"text": "\n\nThe search results provide the current weather conditions in San Francisco. According to the data, as of 2:00 PM on August 30, 2024, the temperature in San Francisco is 70\u00b0F (21.1\u00b0C) with partly cloudy skies. The wind is blowing from the west-northwest at around 12 mph (19 km/h). The humidity is 59% and visibility is 9 miles (16 km). Overall, it looks like a nice late summer day in San Francisco with comfortable temperatures and partly sunny conditions.",
"type": "text",
"index": 0
}
],
"additional_kwargs": {},
"response_metadata": {
"stop_reason": "end_turn",
"stop_sequence": null
},
"type": "ai",
"name": null,
"id": "run-8fecc61d-3d9f-4e16-8e8a-92f702be498a",
"example": false,
"tool_calls": [],
"invalid_tool_calls": [],
"usage_metadata": {
"input_tokens": 837,
"output_tokens": 124,
"total_tokens": 961
}
}
]
},
"next": [],
"tasks": [],
"metadata": {
"step": 3,
"run_id": "1ef67140-eb23-684b-8253-91d4c90bb05e",
"source": "loop",
"writes": {
"agent": {
"messages": [
{
"id": "run-8fecc61d-3d9f-4e16-8e8a-92f702be498a",
"name": null,
"type": "ai",
"content": [
{
"text": "\n\nThe search results provide the current weather conditions in San Francisco. According to the data, as of 2:00 PM on August 30, 2024, the temperature in San Francisco is 70\u00b0F (21.1\u00b0C) with partly cloudy skies. The wind is blowing from the west-northwest at around 12 mph (19 km/h). The humidity is 59% and visibility is 9 miles (16 km). Overall, it looks like a nice late summer day in San Francisco with comfortable temperatures and partly sunny conditions.",
"type": "text",
"index": 0
}
],
"example": false,
"tool_calls": [],
"usage_metadata": {
"input_tokens": 837,
"total_tokens": 961,
"output_tokens": 124
},
"additional_kwargs": {},
"response_metadata": {
"stop_reason": "end_turn",
"stop_sequence": null
},
"invalid_tool_calls": []
}
]
}
},
"user_id": "",
"graph_id": "agent",
"thread_id": "5cb1e8a1-34b3-4a61-a34e-71a9799bd00d",
"created_by": "system",
"assistant_id": "fe096781-5601-53d2-b2f6-0d3403f7e9ca"
},
"created_at": "2024-08-30T21:09:00.079909+00:00",
"checkpoint_id": "1ef67141-3ca2-6fae-8003-fe96832e57d6",
"parent_checkpoint_id": "1ef67141-2129-6b37-8002-61fc3bf69cb5"
}
We can also just print the content of the last AIMessage:
=== "Python"
```python
print(final_result['values']['messages'][-1]['content'][0]['text'])
```
=== "Javascript"
```js
console.log(finalResult['values']['messages'][finalResult['values']['messages'].length-1]['content'][0]['text']);
```
=== "CURL"
```bash
curl --request GET \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/state | jq -r '.values.messages[-1].content.[0].text'
```
Output:
The search results provide the current weather conditions in San Francisco. According to the data, as of 2:00 PM on August 30, 2024, the temperature in San Francisco is 70°F (21.1°C) with partly cloudy skies. The wind is blowing from the west-northwest at around 12 mph (19 km/h). The humidity is 59% and visibility is 9 miles (16 km). Overall, it looks like a nice late summer day in San Francisco with comfortable temperatures and partly sunny conditions.
@@ -0,0 +1,36 @@
# Debug LangSmith traces
This guide explains how to open LangSmith traces in LangGraph Studio for interactive investigation and debugging.
## Open deployed threads
1. Open the LangSmith trace, selecting the root run.
2. Click "Run in Studio".
This will open LangGraph Studio connected to the associated LangGraph Platform deployment with the trace's parent thread selected.
## Testing local agents with remote traces
This section explains how to test a local agent against remote traces from LangSmith. This enables you to use production traces as input for local testing, allowing you to debug and verify agent modifications in your development environment.
### Requirements
- A LangSmith traced thread
- A locally running agent. See [here](../how-tos/studio/quick_start.md#local-development-server) for setup
instructions.
!!! info "Local agent requirements"
- langgraph>=0.3.18
- langgraph-api>=0.0.32
- Contains the same set of nodes present in the remote trace
### Cloning Thread
1. Open the LangSmith trace, selecting the root run.
2. Click the dropdown next to "Run in Studio".
3. Enter your local agent's URL.
4. Select "Clone thread locally".
5. If multiple graphs exist, select the target graph.
A new thread will be created in your local agent with the thread history inferred and copied from the remote thread, and you will be navigated to LangGraph Studio for your locally running application.
@@ -0,0 +1,84 @@
# Configurable Headers
LangGraph allows runtime configuration to modify agent behavior and permissions dynamically. When using the [LangGraph Platform](../quick_start.md), you can pass this configuration in the request body (`config`) or specific request headers. This enables adjustments based on user identity or other request data.
For privacy, control which headers are passed to the runtime configuration via the `http.configurable_headers` section in your `langgraph.json` file.
Here's how to customize the included and excluded headers:
```json
{
"http": {
"configurable_headers": {
"include": ["x-user-id", "x-organization-id", "my-prefix-*"],
"exclude": ["authorization", "x-api-key"]
}
}
}
```
The `include` and `exclude` lists accept exact header names or patterns using `*` to match any number of characters. For your security, no other regex patterns are supported.
## Using within your graph
You can access the included headers in your graph using the `config` argument of any node.
```python
def my_node(state, config):
organization_id = config["configurable"].get("x-organization-id")
...
```
Or by fetching from context (useful in tools and or within other nested functions).
```python
from langgraph.config import get_config
def search_everything(query: str):
organization_id = get_config()["configurable"].get("x-organization-id")
...
```
You can even use this to dynamically compile the graph.
```python
# my_graph.py.
import contextlib
@contextlib.asynccontextmanager
async def generate_agent(config):
organization_id = config["configurable"].get("x-organization-id")
if organization_id == "org1":
graph = ...
yield graph
else:
graph = ...
yield graph
```
```json
{
"graphs": {"agent": "my_grph.py:generate_agent"}
}
```
### Opt-out of configurable headers
If you'd like to opt-out of configurable headers, you can simply set a wildcard pattern in the `exclude` list:
```json
{
"http": {
"configurable_headers": {
"exclude": ["*"]
}
}
}
```
This will exclude all headers from being added to your run's configuration.
Note that exclusions take precedence over inclusions.
@@ -0,0 +1,332 @@
# Manage assistants
In this guide we will show how to create, configure, and manage an [assistant](../../concepts/assistants.md).
First, as a brief refresher on the concept of runtime context, consider the following simple `call_model` node and context schema. Observe that this node tries to read and use the `model_provider` as defined by the `Runtime` object's `context` property.
=== "Python"
```python
@dataclass
class ContextSchema:
llm_provider: str = "anthropic"
builder = StateGraph(AgentState, context_schema=ContextSchema)
def call_model(state, runtime: Runtime[ContextSchema]):
messages = state["messages"]
model = _get_model(runtime.context.llm_provider)
response = model.invoke(messages)
# We return a list, because this will get added to the existing list
return {"messages": [response]}
```
=== "Javascript"
```js
import { Annotation } from "@langchain/langgraph";
const ConfigSchema = Annotation.Root({
model_name: Annotation<string>,
system_prompt:
});
const builder = new StateGraph(AgentState, ConfigSchema)
function callModel(state: State, config: RunnableConfig) {
const messages = state.messages;
const modelName = config.configurable?.model_name ?? "anthropic";
const model = _getModel(modelName);
const response = model.invoke(messages);
// We return a list, because this will get added to the existing list
return { messages: [response] };
}
```
:::python
For more information on runtime context, [see here](../../concepts/low_level.md#runtime-context).
:::
## Create an assistant
### LangGraph SDK
To create an assistant, use the [LangGraph SDK](../../concepts/sdk.md) `create` method. See the [Python](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/#langgraph_sdk.client.AssistantsClient.create) and [JS](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#create) SDK reference docs for more information.
This example uses the same configuration schema as above, and creates an assistant with `model_name` set to `openai`.
=== "Python"
```python
from langgraph_sdk import get_client
client = get_client(url=<DEPLOYMENT_URL>)
openai_assistant = await client.assistants.create(
# "agent" is the name of a graph we deployed
"agent", config={"configurable": {"model_name": "openai"}}, name="Open AI Assistant"
)
print(openai_assistant)
```
=== "Javascript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });
const openAIAssistant = await client.assistants.create({
graphId: 'agent',
name: "Open AI Assistant",
config: { "configurable": { "model_name": "openai" } },
});
console.log(openAIAssistant);
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/assistants \
--header 'Content-Type: application/json' \
--data '{"graph_id":"agent", "config":{"configurable":{"model_name":"openai"}}, "name": "Open AI Assistant"}'
```
Output:
{
"assistant_id": "62e209ca-9154-432a-b9e9-2d75c7a9219b",
"graph_id": "agent",
"name": "Open AI Assistant"
"config": {
"configurable": {
"model_name": "openai"
}
},
"metadata": {}
"created_at": "2024-08-31T03:09:10.230718+00:00",
"updated_at": "2024-08-31T03:09:10.230718+00:00",
}
### LangGraph Platform UI
You can also create assistants from the LangGraph Platform UI.
Inside your deployment, select the "Assistants" tab. This will load a table of all of the assistants in your deployment, across all graphs.
To create a new assistant, select the "+ New assistant" button. This will open a form where you can specify the graph this assistant is for, as well as provide a name, description, and the desired configuration for the assistant based on the configuration schema for that graph.
To confirm, click "Create assistant". This will take you to [LangGraph Studio](../../concepts/langgraph_studio.md) where you can test the assistant. If you go back to the "Assistants" tab in the deployment, you will see the newly created assistant in the table.
## Use an assistant
### LangGraph SDK
We have now created an assistant called "Open AI Assistant" that has `model_name` defined as `openai`. We can now use this assistant with this configuration:
=== "Python"
```python
thread = await client.threads.create()
input = {"messages": [{"role": "user", "content": "who made you?"}]}
async for event in client.runs.stream(
thread["thread_id"],
# this is where we specify the assistant id to use
openai_assistant["assistant_id"],
input=input,
stream_mode="updates",
):
print(f"Receiving event of type: {event.event}")
print(event.data)
print("\n\n")
```
=== "Javascript"
```js
const thread = await client.threads.create();
const input = { "messages": [{ "role": "user", "content": "who made you?" }] };
const streamResponse = client.runs.stream(
thread["thread_id"],
// this is where we specify the assistant id to use
openAIAssistant["assistant_id"],
{
input,
streamMode: "updates"
}
);
for await (const event of streamResponse) {
console.log(`Receiving event of type: ${event.event}`);
console.log(event.data);
console.log("\n\n");
}
```
=== "CURL"
```bash
thread_id=$(curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}' | jq -r '.thread_id') && \
curl --request POST \
--url "<DEPLOYMENT_URL>/threads/${thread_id}/runs/stream" \
--header 'Content-Type: application/json' \
--data '{
"assistant_id": <OPENAI_ASSISTANT_ID>,
"input": {
"messages": [
{
"role": "user",
"content": "who made you?"
}
]
},
"stream_mode": [
"updates"
]
}' | \
sed 's/\r$//' | \
awk '
/^event:/ {
if (data_content != "") {
print data_content "\n"
}
sub(/^event: /, "Receiving event of type: ", $0)
printf "%s...\n", $0
data_content = ""
}
/^data:/ {
sub(/^data: /, "", $0)
data_content = $0
}
END {
if (data_content != "") {
print data_content "\n\n"
}
}
'
```
Output:
```
Receiving event of type: metadata
{'run_id': '1ef6746e-5893-67b1-978a-0f1cd4060e16'}
Receiving event of type: updates
{'agent': {'messages': [{'content': 'I was created by OpenAI, a research organization focused on developing and advancing artificial intelligence technology.', 'additional_kwargs': {}, 'response_metadata': {'finish_reason': 'stop', 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_157b3831f5'}, 'type': 'ai', 'name': None, 'id': 'run-e1a6b25c-8416-41f2-9981-f9cfe043f414', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]}}
```
### LangGraph Platform UI
Inside your deployment, select the "Assistants" tab. For the assistant you would like to use, click the "Studio" button. This will open LangGraph Studio with the selected assistant. When you submit an input (either in Graph or Chat mode), the selected assistant and its configuration will be used.
## Create a new version for your assistant
### LangGraph SDK
To edit the assistant, use the `update` method. This will create a new version of the assistant with the provided edits. See the [Python](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/#langgraph_sdk.client.AssistantsClient.update) and [JS](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#update) SDK reference docs for more information.
!!! note "Note"
You must pass in the ENTIRE config (and metadata if you are using it). The update endpoint creates new versions completely from scratch and does not rely on previous versions.
For example, to update your assistant's system prompt:
=== "Python"
```python
openai_assistant_v2 = await client.assistants.update(
openai_assistant["assistant_id"],
config={
"configurable": {
"model_name": "openai",
"system_prompt": "You are an unhelpful assistant!",
}
},
)
```
=== "Javascript"
```js
const openaiAssistantV2 = await client.assistants.update(
openai_assistant["assistant_id"],
{
config: {
configurable: {
model_name: 'openai',
system_prompt: 'You are an unhelpful assistant!',
},
},
});
```
=== "CURL"
```bash
curl --request PATCH \
--url <DEPOLYMENT_URL>/assistants/<ASSISTANT_ID> \
--header 'Content-Type: application/json' \
--data '{
"config": {"model_name": "openai", "system_prompt": "You are an unhelpful assistant!"}
}'
```
This will create a new version of the assistant with the updated parameters and set this as the active version of your assistant. If you now run your graph and pass in this assistant id, it will use this latest version.
### LangGraph Platform UI
You can also edit assistants from the LangGraph Platform UI.
Inside your deployment, select the "Assistants" tab. This will load a table of all of the assistants in your deployment, across all graphs.
To edit an existing assistant, select the "Edit" button for the specified assistant. This will open a form where you can edit the assistant's name, description, and configuration.
Additionally, if using LangGraph Studio, you can edit the assistants and create new versions via the "Manage Assistants" button.
## Use a previous assistant version
### LangGraph SDK
You can also change the active version of your assistant. To do so, use the `setLatest` method.
In the example above, to rollback to the first version of the assistant:
=== "Python"
```python
await client.assistants.set_latest(openai_assistant['assistant_id'], 1)
```
=== "Javascript"
```js
await client.assistants.setLatest(openaiAssistant['assistant_id'], 1);
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/assistants/<ASSISTANT_ID>/latest \
--header 'Content-Type: application/json' \
--data '{
"version": 1
}'
```
If you now run your graph and pass in this assistant id, it will use the first version of the assistant.
### LangGraph Platform UI
If using LangGraph Studio, to set the active version of your assistant, click the "Manage Assistants" button and locate the assistant you would like to use. Select the assistant and the version, and then click the "Active" toggle. This will update the assistant to make the selected version active.
!!! warning "Deleting Assistants"
Deleting as assistant will delete ALL of its versions. There is currently no way to delete a single version, but by pointing your assistant to the correct version you can skip any versions that you don't wish to use.
+184
View File
@@ -0,0 +1,184 @@
# Use cron jobs
Sometimes you don't want to run your graph based on user interaction, but rather you would like to schedule your graph to run on a schedule - for example if you wish for your graph to compose and send out a weekly email of to-dos for your team. LangGraph Platform allows you to do this without having to write your own script by using the `Crons` client. To schedule a graph job, you need to pass a [cron expression](https://crontab.cronhub.io/) to inform the client when you want to run the graph. `Cron` jobs are run in the background and do not interfere with normal invocations of the graph.
## Setup
First, let's set up our SDK client, assistant, and thread:
=== "Python"
```python
from langgraph_sdk import get_client
client = get_client(url=<DEPLOYMENT_URL>)
# Using the graph deployed with the name "agent"
assistant_id = "agent"
# create thread
thread = await client.threads.create()
print(thread)
```
=== "Javascript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });
// Using the graph deployed with the name "agent"
const assistantId = "agent";
// create thread
const thread = await client.threads.create();
console.log(thread);
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/assistants/search \
--header 'Content-Type: application/json' \
--data '{
"limit": 10,
"offset": 0
}' | jq -c 'map(select(.config == null or .config == {})) | .[0].graph_id' && \
curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}'
```
Output:
{
'thread_id': '9dde5490-2b67-47c8-aa14-4bfec88af217',
'created_at': '2024-08-30T23:07:38.242730+00:00',
'updated_at': '2024-08-30T23:07:38.242730+00:00',
'metadata': {},
'status': 'idle',
'config': {},
'values': None
}
## Cron job on a thread
To create a cron job associated with a specific thread, you can write:
=== "Python"
```python
# This schedules a job to run at 15:27 (3:27PM) every day
cron_job = await client.crons.create_for_thread(
thread["thread_id"],
assistant_id,
schedule="27 15 * * *",
input={"messages": [{"role": "user", "content": "What time is it?"}]},
)
```
=== "Javascript"
```js
// This schedules a job to run at 15:27 (3:27PM) every day
const cronJob = await client.crons.create_for_thread(
thread["thread_id"],
assistantId,
{
schedule: "27 15 * * *",
input: { messages: [{ role: "user", content: "What time is it?" }] }
}
);
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/crons \
--header 'Content-Type: application/json' \
--data '{
"assistant_id": <ASSISTANT_ID>,
}'
```
Note that it is **very** important to delete `Cron` jobs that are no longer useful. Otherwise you could rack up unwanted API charges to the LLM! You can delete a `Cron` job using the following code:
=== "Python"
```python
await client.crons.delete(cron_job["cron_id"])
```
=== "Javascript"
```js
await client.crons.delete(cronJob["cron_id"]);
```
=== "CURL"
```bash
curl --request DELETE \
--url <DEPLOYMENT_URL>/runs/crons/<CRON_ID>
```
## Cron job stateless
You can also create stateless cron jobs by using the following code:
=== "Python"
```python
# This schedules a job to run at 15:27 (3:27PM) every day
cron_job_stateless = await client.crons.create(
assistant_id,
schedule="27 15 * * *",
input={"messages": [{"role": "user", "content": "What time is it?"}]},
)
```
=== "Javascript"
```js
// This schedules a job to run at 15:27 (3:27PM) every day
const cronJobStateless = await client.crons.create(
assistantId,
{
schedule: "27 15 * * *",
input: { messages: [{ role: "user", content: "What time is it?" }] }
}
);
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/runs/crons \
--header 'Content-Type: application/json' \
--data '{
"assistant_id": <ASSISTANT_ID>,
}'
```
Again, remember to delete your job once you are done with it!
=== "Python"
```python
await client.crons.delete(cron_job_stateless["cron_id"])
```
=== "Javascript"
```js
await client.crons.delete(cronJobStateless["cron_id"]);
```
=== "CURL"
```bash
curl --request DELETE \
--url <DEPLOYMENT_URL>/runs/crons/<CRON_ID>
```
@@ -0,0 +1,12 @@
# Add node to dataset
This guide shows how to add examples to [LangSmith datasets](https://docs.smith.langchain.com/evaluation/how_to_guides#dataset-management) from nodes in the thread log. This is useful to evaluate individual steps of the agent.
1. Select a thread.
2. Click on the `Add to Dataset` button.
3. Select nodes whose input/output you want to add to a dataset.
4. For each selected node, select the target dataset to create the example in. By default a dataset for the specific assistant and node will be selected. If this dataset does not yet exist, it will be created.
5. Edit the example's input/output as needed before adding it to the dataset.
6. Select "Add to dataset" at the bottom of the page to add all selected nodes to their respective datasets.
See [Evaluating intermediate steps](https://docs.smith.langchain.com/evaluation/how_to_guides/langgraph#evaluating-intermediate-steps) for more details on how to evaluate intermediate steps.
@@ -0,0 +1,255 @@
# Enqueue
This guide assumes knowledge of what double-texting is, which you can learn about in the [double-texting conceptual guide](../../concepts/double_texting.md).
The guide covers the `enqueue` option for double texting, which adds the interruptions to a queue and executes them in the order they are received by the client. Below is a quick example of using the `enqueue` option.
## Setup
First, we will define a quick helper function for printing out JS and CURL model outputs (you can skip this if using Python):
=== "Javascript"
```js
function prettyPrint(m) {
const padded = " " + m['type'] + " ";
const sepLen = Math.floor((80 - padded.length) / 2);
const sep = "=".repeat(sepLen);
const secondSep = sep + (padded.length % 2 ? "=" : "");
console.log(`${sep}${padded}${secondSep}`);
console.log("\n\n");
console.log(m.content);
}
```
=== "CURL"
```bash
# PLACE THIS IN A FILE CALLED pretty_print.sh
pretty_print() {
local type="$1"
local content="$2"
local padded=" $type "
local total_width=80
local sep_len=$(( (total_width - ${#padded}) / 2 ))
local sep=$(printf '=%.0s' $(eval "echo {1.."${sep_len}"}"))
local second_sep=$sep
if (( (total_width - ${#padded}) % 2 )); then
second_sep="${second_sep}="
fi
echo "${sep}${padded}${second_sep}"
echo
echo "$content"
}
```
Then, let's import our required packages and instantiate our client, assistant, and thread.
=== "Python"
```python
import asyncio
import httpx
from langchain_core.messages import convert_to_messages
from langgraph_sdk import get_client
client = get_client(url=<DEPLOYMENT_URL>)
# Using the graph deployed with the name "agent"
assistant_id = "agent"
thread = await client.threads.create()
```
=== "Javascript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });
// Using the graph deployed with the name "agent"
const assistantId = "agent";
const thread = await client.threads.create();
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}'
```
## Create runs
Now let's start two runs, with the second interrupting the first one with a multitask strategy of "enqueue":
=== "Python"
```python
first_run = await client.runs.create(
thread["thread_id"],
assistant_id,
input={"messages": [{"role": "user", "content": "what's the weather in sf?"}]},
)
second_run = await client.runs.create(
thread["thread_id"],
assistant_id,
input={"messages": [{"role": "user", "content": "what's the weather in nyc?"}]},
multitask_strategy="enqueue",
)
```
=== "Javascript"
```js
const firstRun = await client.runs.create(
thread["thread_id"],
assistantId,
input={"messages": [{"role": "user", "content": "what's the weather in sf?"}]},
)
const secondRun = await client.runs.create(
thread["thread_id"],
assistantId,
input={"messages": [{"role": "user", "content": "what's the weather in nyc?"}]},
multitask_strategy="enqueue",
)
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOY<ENT_URL>>/threads/<THREAD_ID>/runs \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {\"messages\": [{\"role\": \"human\", \"content\": \"what\'s the weather in sf?\"}]},
}" && curl --request POST \
--url <DEPLOY<ENT_URL>>/threads/<THREAD_ID>/runs \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {\"messages\": [{\"role\": \"human\", \"content\": \"what\'s the weather in nyc?\"}]},
\"multitask_strategy\": \"enqueue\"
}"
```
## View run results
Verify that the thread has data from both runs:
=== "Python"
```python
# wait until the second run completes
await client.runs.join(thread["thread_id"], second_run["run_id"])
state = await client.threads.get_state(thread["thread_id"])
for m in convert_to_messages(state["values"]["messages"]):
m.pretty_print()
```
=== "Javascript"
```js
await client.runs.join(thread["thread_id"], secondRun["run_id"]);
const state = await client.threads.getState(thread["thread_id"]);
for (const m of state["values"]["messages"]) {
prettyPrint(m);
}
```
=== "CURL"
```bash
source pretty_print.sh && curl --request GET \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/<RUN_ID>/join && \
curl --request GET --url <DEPLOYMENT_URL>/threads/<THREAD_ID>/state | \
jq -c '.values.messages[]' | while read -r element; do
type=$(echo "$element" | jq -r '.type')
content=$(echo "$element" | jq -r '.content | if type == "array" then tostring else . end')
pretty_print "$type" "$content"
done
```
Output:
================================ Human Message =================================
what's the weather in sf?
================================== Ai Message ==================================
[{'id': 'toolu_01Dez1sJre4oA2Y7NsKJV6VT', 'input': {'query': 'weather in san francisco'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]
Tool Calls:
tavily_search_results_json (toolu_01Dez1sJre4oA2Y7NsKJV6VT)
Call ID: toolu_01Dez1sJre4oA2Y7NsKJV6VT
Args:
query: weather in san francisco
================================= Tool Message =================================
Name: tavily_search_results_json
[{"url": "https://www.accuweather.com/en/us/san-francisco/94103/weather-forecast/347629", "content": "Get the current and future weather conditions for San Francisco, CA, including temperature, precipitation, wind, air quality and more. See the hourly and 10-day outlook, radar maps, alerts and allergy information."}]
================================== Ai Message ==================================
According to AccuWeather, the current weather conditions in San Francisco are:
Temperature: 57°F (14°C)
Conditions: Mostly Sunny
Wind: WSW 10 mph
Humidity: 72%
The forecast for the next few days shows partly sunny skies with highs in the upper 50s to mid 60s F (14-18°C) and lows in the upper 40s to low 50s F (9-11°C). Typical mild, dry weather for San Francisco this time of year.
Some key details from the AccuWeather forecast:
Today: Mostly sunny, high of 62°F (17°C)
Tonight: Partly cloudy, low of 49°F (9°C)
Tomorrow: Partly sunny, high of 59°F (15°C)
Saturday: Mostly sunny, high of 64°F (18°C)
Sunday: Partly sunny, high of 61°F (16°C)
So in summary, expect seasonable spring weather in San Francisco over the next several days, with a mix of sun and clouds and temperatures ranging from the upper 40s at night to the low 60s during the days. Typical dry conditions with no rain in the forecast.
================================ Human Message =================================
what's the weather in nyc?
================================== Ai Message ==================================
[{'text': 'Here are the current weather conditions and forecast for New York City:', 'type': 'text'}, {'id': 'toolu_01FFft5Sx9oS6AdVJuRWWcGp', 'input': {'query': 'weather in new york city'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]
Tool Calls:
tavily_search_results_json (toolu_01FFft5Sx9oS6AdVJuRWWcGp)
Call ID: toolu_01FFft5Sx9oS6AdVJuRWWcGp
Args:
query: weather in new york city
================================= Tool Message =================================
Name: tavily_search_results_json
[{"url": "https://www.weatherapi.com/", "content": "{'location': {'name': 'New York', 'region': 'New York', 'country': 'United States of America', 'lat': 40.71, 'lon': -74.01, 'tz_id': 'America/New_York', 'localtime_epoch': 1718734479, 'localtime': '2024-06-18 14:14'}, 'current': {'last_updated_epoch': 1718733600, 'last_updated': '2024-06-18 14:00', 'temp_c': 29.4, 'temp_f': 84.9, 'is_day': 1, 'condition': {'text': 'Sunny', 'icon': '//cdn.weatherapi.com/weather/64x64/day/113.png', 'code': 1000}, 'wind_mph': 2.2, 'wind_kph': 3.6, 'wind_degree': 158, 'wind_dir': 'SSE', 'pressure_mb': 1025.0, 'pressure_in': 30.26, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 63, 'cloud': 0, 'feelslike_c': 31.3, 'feelslike_f': 88.3, 'windchill_c': 28.3, 'windchill_f': 82.9, 'heatindex_c': 29.6, 'heatindex_f': 85.3, 'dewpoint_c': 18.4, 'dewpoint_f': 65.2, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 7.0, 'gust_mph': 16.5, 'gust_kph': 26.5}}"}]
================================== Ai Message ==================================
According to the weather data from WeatherAPI:
Current Conditions in New York City (as of 2:00 PM local time):
- Temperature: 85°F (29°C)
- Conditions: Sunny
- Wind: 2 mph (4 km/h) from the SSE
- Humidity: 63%
- Heat Index: 85°F (30°C)
The forecast shows sunny and warm conditions persisting over the next few days:
Today: Sunny, high of 85°F (29°C)
Tonight: Clear, low of 68°F (20°C)
Tomorrow: Sunny, high of 88°F (31°C)
Thursday: Mostly sunny, high of 90°F (32°C)
Friday: Partly cloudy, high of 87°F (31°C)
So New York City is experiencing beautiful sunny weather with seasonably warm temperatures in the mid-to-upper 80s Fahrenheit (around 30°C). Humidity is moderate in the 60% range. Overall, ideal late spring/early summer conditions for being outdoors in the city over the next several days.
@@ -0,0 +1,538 @@
# How to implement Generative User Interfaces with LangGraph
!!! info "Prerequisites"
- [LangGraph Platform](../../concepts/langgraph_platform.md)
- [LangGraph Server](../../concepts/langgraph_server.md)
- [`useStream()` React Hook](./use_stream_react.md)
Generative user interfaces (Generative UI) allows agents to go beyond text and generate rich user interfaces. This enables creating more interactive and context-aware applications where the UI adapts based on the conversation flow and AI responses.
![Generative UI Sample](./img/generative_ui_sample.jpg)
LangGraph Platform supports colocating your React components with your graph code. This allows you to focus on building specific UI components for your graph while easily plugging into existing chat interfaces such as [Agent Chat](https://agentchat.vercel.app) and loading the code only when actually needed.
## Tutorial
### 1. Define and configure UI components
First, create your first UI component. For each component you need to provide an unique identifier that will be used to reference the component in your graph code.
```tsx title="src/agent/ui.tsx"
const WeatherComponent = (props: { city: string }) => {
return <div>Weather for {props.city}</div>;
};
export default {
weather: WeatherComponent,
};
```
Next, define your UI components in your `langgraph.json` configuration:
=== "Python agent"
```json title="langgraph.json"
{
"node_version": "20",
"graphs": {
"agent": "./src/agent.py:graph"
},
"ui": {
"agent": "./src/agent/ui.tsx"
}
}
```
=== "JS agent"
```json title="langgraph.json"
{
"node_version": "20",
"graphs": {
"agent": "./src/agent/index.ts:graph"
},
"ui": {
"agent": "./src/agent/ui.tsx"
}
}
```
The `ui` section points to the UI components that will be used by graphs. By default, we recommend using the same key as the graph name, but you can split out the components however you like, see [Customise the namespace of UI components](#customise-the-namespace-of-ui-components) for more details.
LangGraph Platform will automatically bundle your UI components code and styles and serve them as external assets that can be loaded by the `LoadExternalComponent` component. Some dependencies such as `react` and `react-dom` will be automatically excluded from the bundle.
CSS and Tailwind 4.x is also supported out of the box, so you can freely use Tailwind classes as well as `shadcn/ui` in your UI components.
=== "`src/agent/ui.tsx`"
```tsx
import "./styles.css";
const WeatherComponent = (props: { city: string }) => {
return <div className="bg-red-500">Weather for {props.city}</div>;
};
export default {
weather: WeatherComponent,
};
```
=== "`src/agent/styles.css`"
```css
@import "tailwindcss";
```
### 2. Send the UI components in your graph
=== "Python"
```python title="src/agent.py"
import uuid
from typing import Annotated, Sequence, TypedDict
from langchain_core.messages import AIMessage, BaseMessage
from langchain_openai import ChatOpenAI
from langgraph.graph import StateGraph
from langgraph.graph.message import add_messages
from langgraph.graph.ui import AnyUIMessage, ui_message_reducer, push_ui_message
class AgentState(TypedDict): # noqa: D101
messages: Annotated[Sequence[BaseMessage], add_messages]
ui: Annotated[Sequence[AnyUIMessage], ui_message_reducer]
async def weather(state: AgentState):
class WeatherOutput(TypedDict):
city: str
weather: WeatherOutput = (
await ChatOpenAI(model="gpt-4o-mini")
.with_structured_output(WeatherOutput)
.with_config({"tags": ["nostream"]})
.ainvoke(state["messages"])
)
message = AIMessage(
id=str(uuid.uuid4()),
content=f"Here's the weather for {weather['city']}",
)
# Emit UI elements associated with the message
push_ui_message("weather", weather, message=message)
return {"messages": [message]}
workflow = StateGraph(AgentState)
workflow.add_node(weather)
workflow.add_edge("__start__", "weather")
graph = workflow.compile()
```
=== "JS"
Use the `typedUi` utility to emit UI elements from your agent nodes:
```typescript title="src/agent/index.ts"
import {
typedUi,
uiMessageReducer,
} from "@langchain/langgraph-sdk/react-ui/server";
import { ChatOpenAI } from "@langchain/openai";
import { v4 as uuidv4 } from "uuid";
import { z } from "zod";
import type ComponentMap from "./ui.js";
import {
Annotation,
MessagesAnnotation,
StateGraph,
type LangGraphRunnableConfig,
} from "@langchain/langgraph";
const AgentState = Annotation.Root({
...MessagesAnnotation.spec,
ui: Annotation({ reducer: uiMessageReducer, default: () => [] }),
});
export const graph = new StateGraph(AgentState)
.addNode("weather", async (state, config) => {
// Provide the type of the component map to ensure
// type safety of `ui.push()` calls as well as
// pushing the messages to the `ui` and sending a custom event as well.
const ui = typedUi<typeof ComponentMap>(config);
const weather = await new ChatOpenAI({ model: "gpt-4o-mini" })
.withStructuredOutput(z.object({ city: z.string() }))
.withConfig({ tags: ["nostream"] })
.invoke(state.messages);
const response = {
id: uuidv4(),
type: "ai",
content: `Here's the weather for ${weather.city}`,
};
// Emit UI elements associated with the AI message
ui.push({ name: "weather", props: weather }, { message: response });
return { messages: [response] };
})
.addEdge("__start__", "weather")
.compile();
```
### 3. Handle UI elements in your React application
On the client side, you can use `useStream()` and `LoadExternalComponent` to display the UI elements.
```tsx title="src/app/page.tsx"
"use client";
import { useStream } from "@langchain/langgraph-sdk/react";
import { LoadExternalComponent } from "@langchain/langgraph-sdk/react-ui";
export default function Page() {
const { thread, values } = useStream({
apiUrl: "http://localhost:2024",
assistantId: "agent",
});
return (
<div>
{thread.messages.map((message) => (
<div key={message.id}>
{message.content}
{values.ui
?.filter((ui) => ui.metadata?.message_id === message.id)
.map((ui) => (
<LoadExternalComponent key={ui.id} stream={thread} message={ui} />
))}
</div>
))}
</div>
);
}
```
Behind the scenes, `LoadExternalComponent` will fetch the JS and CSS for the UI components from LangGraph Platform and render them in a shadow DOM, thus ensuring style isolation from the rest of your application.
## How-to guides
### Provide custom components on the client side
If you already have the components loaded in your client application, you can provide a map of such components to be rendered directly without fetching the UI code from LangGraph Platform.
```tsx
const clientComponents = {
weather: WeatherComponent,
};
<LoadExternalComponent
stream={thread}
message={ui}
components={clientComponents}
/>;
```
### Show loading UI when components are loading
You can provide a fallback UI to be rendered when the components are loading.
```tsx
<LoadExternalComponent
stream={thread}
message={ui}
fallback={<div>Loading...</div>}
/>
```
### Customise the namespace of UI components.
By default `LoadExternalComponent` will use the `assistantId` from `useStream()` hook to fetch the code for UI components. You can customise this by providing a `namespace` prop to the `LoadExternalComponent` component.
=== "`src/app/page.tsx`"
```tsx
<LoadExternalComponent
stream={thread}
message={ui}
namespace="custom-namespace"
/>
```
=== "`langgraph.json`"
```json
{
"ui": {
"custom-namespace": "./src/agent/ui.tsx"
}
}
```
### Access and interact with the thread state from the UI component
You can access the thread state inside the UI component by using the `useStreamContext` hook.
```tsx
import { useStreamContext } from "@langchain/langgraph-sdk/react-ui";
const WeatherComponent = (props: { city: string }) => {
const { thread, submit } = useStreamContext();
return (
<>
<div>Weather for {props.city}</div>
<button
onClick={() => {
const newMessage = {
type: "human",
content: `What's the weather in ${props.city}?`,
};
submit({ messages: [newMessage] });
}}
>
Retry
</button>
</>
);
};
```
### Pass additional context to the client components
You can pass additional context to the client components by providing a `meta` prop to the `LoadExternalComponent` component.
```tsx
<LoadExternalComponent stream={thread} message={ui} meta={{ userId: "123" }} />
```
Then, you can access the `meta` prop in the UI component by using the `useStreamContext` hook.
```tsx
import { useStreamContext } from "@langchain/langgraph-sdk/react-ui";
const WeatherComponent = (props: { city: string }) => {
const { meta } = useStreamContext<
{ city: string },
{ MetaType: { userId?: string } }
>();
return (
<div>
Weather for {props.city} (user: {meta?.userId})
</div>
);
};
```
### Streaming UI messages from the server
You can stream UI messages before the node execution is finished by using the `onCustomEvent` callback of the `useStream()` hook. This is especially useful when updating the UI component as the LLM is generating the response.
```tsx
import { uiMessageReducer } from "@langchain/langgraph-sdk/react-ui";
const { thread, submit } = useStream({
apiUrl: "http://localhost:2024",
assistantId: "agent",
onCustomEvent: (event, options) => {
options.mutate((prev) => {
const ui = uiMessageReducer(prev.ui ?? [], event);
return { ...prev, ui };
});
},
});
```
Then you can push updates to the UI component by calling `ui.push()` / `push_ui_message()` with the same ID as the UI message you wish to update.
=== "Python"
```python
from typing import Annotated, Sequence, TypedDict
from langchain_anthropic import ChatAnthropic
from langchain_core.messages import AIMessage, AIMessageChunk, BaseMessage
from langgraph.graph import StateGraph
from langgraph.graph.message import add_messages
from langgraph.graph.ui import AnyUIMessage, push_ui_message, ui_message_reducer
class AgentState(TypedDict): # noqa: D101
messages: Annotated[Sequence[BaseMessage], add_messages]
ui: Annotated[Sequence[AnyUIMessage], ui_message_reducer]
class CreateTextDocument(TypedDict):
"""Prepare a document heading for the user."""
title: str
async def writer_node(state: AgentState):
model = ChatAnthropic(model="claude-3-5-sonnet-latest")
message: AIMessage = await model.bind_tools(
tools=[CreateTextDocument],
tool_choice={"type": "tool", "name": "CreateTextDocument"},
).ainvoke(state["messages"])
tool_call = next(
(x["args"] for x in message.tool_calls if x["name"] == "CreateTextDocument"),
None,
)
if tool_call:
ui_message = push_ui_message("writer", tool_call, message=message)
ui_message_id = ui_message["id"]
# We're already streaming the LLM response to the client through UI messages
# so we don't need to stream it again to the `messages` stream mode.
content_stream = model.with_config({"tags": ["nostream"]}).astream(
f"Create a document with the title: {tool_call['title']}"
)
content: AIMessageChunk | None = None
async for chunk in content_stream:
content = content + chunk if content else chunk
push_ui_message(
"writer",
{"content": content.text()},
id=ui_message_id,
message=message,
# Use `merge=rue` to merge props with the existing UI message
merge=True,
)
return {"messages": [message]}
```
=== "JS"
```tsx
import {
Annotation,
MessagesAnnotation,
type LangGraphRunnableConfig,
} from "@langchain/langgraph";
import { z } from "zod";
import { ChatAnthropic } from "@langchain/anthropic";
import {
typedUi,
uiMessageReducer,
} from "@langchain/langgraph-sdk/react-ui/server";
import type { AIMessageChunk } from "@langchain/core/messages";
import type ComponentMap from "./ui";
const AgentState = Annotation.Root({
...MessagesAnnotation.spec,
ui: Annotation({ reducer: uiMessageReducer, default: () => [] }),
});
async function writerNode(
state: typeof AgentState.State,
config: LangGraphRunnableConfig
): Promise<typeof AgentState.Update> {
const ui = typedUi<typeof ComponentMap>(config);
const model = new ChatAnthropic({ model: "claude-3-5-sonnet-latest" });
const message = await model
.bindTools(
[
{
name: "create_text_document",
description: "Prepare a document heading for the user.",
schema: z.object({ title: z.string() }),
},
],
{ tool_choice: { type: "tool", name: "create_text_document" } }
)
.invoke(state.messages);
type ToolCall = { name: "create_text_document"; args: { title: string } };
const toolCall = message.tool_calls?.find(
(tool): tool is ToolCall => tool.name === "create_text_document"
);
if (toolCall) {
const { id, name } = ui.push(
{ name: "writer", props: { title: toolCall.args.title } },
{ message }
);
const contentStream = await model
// We're already streaming the LLM response to the client through UI messages
// so we don't need to stream it again to the `messages` stream mode.
.withConfig({ tags: ["nostream"] })
.stream(`Create a short poem with the topic: ${message.text}`);
let content: AIMessageChunk | undefined;
for await (const chunk of contentStream) {
content = content?.concat(chunk) ?? chunk;
ui.push(
{ id, name, props: { content: content?.text } },
// Use `merge: true` to merge props with the existing UI message
{ message, merge: true }
);
}
}
return { messages: [message] };
}
```
=== "`ui.tsx`"
```tsx
function WriterComponent(props: { title: string; content?: string }) {
return (
<article>
<h2>{props.title}</h2>
<p style={{ whiteSpace: "pre-wrap" }}>{props.content}</p>
</article>
);
}
export default {
weather: WriterComponent,
};
```
### Remove UI messages from state
Similar to how messages can be removed from the state by appending a RemoveMessage you can remove an UI message from the state by calling `remove_ui_message` / `ui.delete` with the ID of the UI message.
=== "Python"
```python
from langgraph.graph.ui import push_ui_message, delete_ui_message
# push message
message = push_ui_message("weather", {"city": "London"})
# remove said message
delete_ui_message(message["id"])
```
=== "JS"
```tsx
// push message
const message = ui.push({ name: "weather", props: { city: "London" } });
// remove said message
ui.delete(message.id);
```
## Learn more
- [JS/TS SDK Reference](../reference/sdk/js_ts_sdk_ref.md)
@@ -0,0 +1,238 @@
# Time travel using Server API
LangGraph provides the [**time travel**](../../concepts/time-travel.md) functionality to resume execution from a prior checkpoint, either replaying the same state or modifying it to explore alternatives. In all cases, resuming past execution produces a new fork in the history.
To time travel using the LangGraph Server API (via the LangGraph SDK):
1. **Run the graph** with initial inputs using [LangGraph SDK](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/)'s @[`client.runs.wait`][client.runs.wait] or @[`client.runs.stream`][client.runs.stream] APIs.
2. **Identify a checkpoint in an existing thread**: Use @[`client.threads.get_history`][client.threads.get_history] method to retrieve the execution history for a specific `thread_id` and locate the desired `checkpoint_id`.
Alternatively, set a [breakpoint](./human_in_the_loop_breakpoint.md) before the node(s) where you want execution to pause. You can then find the most recent checkpoint recorded up to that breakpoint.
3. **(Optional) modify the graph state**: Use the @[`client.threads.update_state`][client.threads.update_state] method to modify the graphs state at the checkpoint and resume execution from alternative state.
4. **Resume execution from the checkpoint**: Use the @[`client.runs.wait`][client.runs.wait] or @[`client.runs.stream`][client.runs.stream] APIs with an input of `None` and the appropriate `thread_id` and `checkpoint_id`.
## Use time travel in a workflow
??? example "Example graph"
```python
from typing_extensions import TypedDict, NotRequired
from langgraph.graph import StateGraph, START, END
from langchain.chat_models import init_chat_model
from langgraph.checkpoint.memory import InMemorySaver
class State(TypedDict):
topic: NotRequired[str]
joke: NotRequired[str]
llm = init_chat_model(
"anthropic:claude-3-7-sonnet-latest",
temperature=0,
)
def generate_topic(state: State):
"""LLM call to generate a topic for the joke"""
msg = llm.invoke("Give me a funny topic for a joke")
return {"topic": msg.content}
def write_joke(state: State):
"""LLM call to write a joke based on the topic"""
msg = llm.invoke(f"Write a short joke about {state['topic']}")
return {"joke": msg.content}
# Build workflow
builder = StateGraph(State)
# Add nodes
builder.add_node("generate_topic", generate_topic)
builder.add_node("write_joke", write_joke)
# Add edges to connect nodes
builder.add_edge(START, "generate_topic")
builder.add_edge("generate_topic", "write_joke")
# Compile
graph = builder.compile()
```
### 1. Run the graph
=== "Python"
```python
from langgraph_sdk import get_client
client = get_client(url=<DEPLOYMENT_URL>)
# Using the graph deployed with the name "agent"
assistant_id = "agent"
# create a thread
thread = await client.threads.create()
thread_id = thread["thread_id"]
# Run the graph
result = await client.runs.wait(
thread_id,
assistant_id,
input={}
)
```
=== "JavaScript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });
// Using the graph deployed with the name "agent"
const assistantID = "agent";
// create a thread
const thread = await client.threads.create();
const threadID = thread["thread_id"];
// Run the graph
const result = await client.runs.wait(
threadID,
assistantID,
{ input: {}}
);
```
=== "cURL"
Create a thread:
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}'
```
Run the graph:
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/wait \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {}
}"
```
### 2. Identify a checkpoint
=== "Python"
```python
# The states are returned in reverse chronological order.
states = await client.threads.get_history(thread_id)
selected_state = states[1]
print(selected_state)
```
=== "JavaScript"
```js
// The states are returned in reverse chronological order.
const states = await client.threads.getHistory(threadID);
const selectedState = states[1];
console.log(selectedState);
```
=== "cURL"
```bash
curl --request GET \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/history \
--header 'Content-Type: application/json'
```
### 3. Update the state (optional)
`update_state` will create a new checkpoint. The new checkpoint will be associated with the same thread, but a new checkpoint ID.
=== "Python"
```python
new_config = await client.threads.update_state(
thread_id,
{"topic": "chickens"},
# highlight-next-line
checkpoint_id=selected_state["checkpoint_id"]
)
print(new_config)
```
=== "JavaScript"
```js
const newConfig = await client.threads.updateState(
threadID,
{
values: { "topic": "chickens" },
checkpointId: selectedState["checkpoint_id"]
}
);
console.log(newConfig);
```
=== "cURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/state \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"checkpoint_id\": <CHECKPOINT_ID>,
\"values\": {\"topic\": \"chickens\"}
}"
```
### 4. Resume execution from the checkpoint
=== "Python"
```python
await client.runs.wait(
thread_id,
assistant_id,
# highlight-next-line
input=None,
# highlight-next-line
checkpoint_id=new_config["checkpoint_id"]
)
```
=== "JavaScript"
```js
await client.runs.wait(
threadID,
assistantID,
{
// highlight-next-line
input: null,
// highlight-next-line
checkpointId: newConfig["checkpoint_id"]
}
);
```
=== "cURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/wait \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"checkpoint_id\": <CHECKPOINT_ID>
}"
```
## Learn more
- [**LangGraph time travel guide**](../../how-tos/human_in_the_loop/time-travel.md): learn more about using time travel in LangGraph.
Binary file not shown.

After

Width:  |  Height:  |  Size: 330 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 721 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 275 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 355 KiB

@@ -0,0 +1,253 @@
# How to use the interrupt option
This guide assumes knowledge of what double-texting is, which you can learn about in the [double-texting conceptual guide](../../concepts/double_texting.md).
The guide covers the `interrupt` option for double texting, which interrupts the prior run of the graph and starts a new one with the double-text. This option does not delete the first run, but rather keeps it in the database but sets its status to `interrupted`. Below is a quick example of using the `interrupt` option.
## Setup
First, we will define a quick helper function for printing out JS and CURL model outputs (you can skip this if using Python):
=== "Javascript"
```js
function prettyPrint(m) {
const padded = " " + m['type'] + " ";
const sepLen = Math.floor((80 - padded.length) / 2);
const sep = "=".repeat(sepLen);
const secondSep = sep + (padded.length % 2 ? "=" : "");
console.log(`${sep}${padded}${secondSep}`);
console.log("\n\n");
console.log(m.content);
}
```
=== "CURL"
```bash
# PLACE THIS IN A FILE CALLED pretty_print.sh
pretty_print() {
local type="$1"
local content="$2"
local padded=" $type "
local total_width=80
local sep_len=$(( (total_width - ${#padded}) / 2 ))
local sep=$(printf '=%.0s' $(eval "echo {1.."${sep_len}"}"))
local second_sep=$sep
if (( (total_width - ${#padded}) % 2 )); then
second_sep="${second_sep}="
fi
echo "${sep}${padded}${second_sep}"
echo
echo "$content"
}
```
Now, let's import our required packages and instantiate our client, assistant, and thread.
=== "Python"
```python
import asyncio
from langchain_core.messages import convert_to_messages
from langgraph_sdk import get_client
client = get_client(url=<DEPLOYMENT_URL>)
# Using the graph deployed with the name "agent"
assistant_id = "agent"
thread = await client.threads.create()
```
=== "Javascript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });
// Using the graph deployed with the name "agent"
const assistantId = "agent";
const thread = await client.threads.create();
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}'
```
## Create runs
Now we can start our two runs and join the second one until it has completed:
=== "Python"
```python
# the first run will be interrupted
interrupted_run = await client.runs.create(
thread["thread_id"],
assistant_id,
input={"messages": [{"role": "user", "content": "what's the weather in sf?"}]},
)
# sleep a bit to get partial outputs from the first run
await asyncio.sleep(2)
run = await client.runs.create(
thread["thread_id"],
assistant_id,
input={"messages": [{"role": "user", "content": "what's the weather in nyc?"}]},
multitask_strategy="interrupt",
)
# wait until the second run completes
await client.runs.join(thread["thread_id"], run["run_id"])
```
=== "Javascript"
```js
// the first run will be interrupted
let interruptedRun = await client.runs.create(
thread["thread_id"],
assistantId,
{ input: { messages: [{ role: "human", content: "what's the weather in sf?" }] } }
);
// sleep a bit to get partial outputs from the first run
await new Promise(resolve => setTimeout(resolve, 2000));
let run = await client.runs.create(
thread["thread_id"],
assistantId,
{
input: { messages: [{ role: "human", content: "what's the weather in nyc?" }] },
multitaskStrategy: "interrupt"
}
);
// wait until the second run completes
await client.runs.join(thread["thread_id"], run["run_id"]);
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOY<ENT_URL>>/threads/<THREAD_ID>/runs \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {\"messages\": [{\"role\": \"human\", \"content\": \"what\'s the weather in sf?\"}]},
}" && sleep 2 && curl --request POST \
--url <DEPLOY<ENT_URL>>/threads/<THREAD_ID>/runs \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {\"messages\": [{\"role\": \"human\", \"content\": \"what\'s the weather in nyc?\"}]},
\"multitask_strategy\": \"interrupt\"
}" && curl --request GET \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/<RUN_ID>/join
```
## View run results
We can see that the thread has partial data from the first run + data from the second run
=== "Python"
```python
state = await client.threads.get_state(thread["thread_id"])
for m in convert_to_messages(state["values"]["messages"]):
m.pretty_print()
```
=== "Javascript"
```js
const state = await client.threads.getState(thread["thread_id"]);
for (const m of state['values']['messages']) {
prettyPrint(m);
}
```
=== "CURL"
```bash
source pretty_print.sh && curl --request GET \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/state | \
jq -c '.values.messages[]' | while read -r element; do
type=$(echo "$element" | jq -r '.type')
content=$(echo "$element" | jq -r '.content | if type == "array" then tostring else . end')
pretty_print "$type" "$content"
done
```
Output:
================================ Human Message =================================
what's the weather in sf?
================================== Ai Message ==================================
[{'id': 'toolu_01MjNtVJwEcpujRGrf3x6Pih', 'input': {'query': 'weather in san francisco'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]
Tool Calls:
tavily_search_results_json (toolu_01MjNtVJwEcpujRGrf3x6Pih)
Call ID: toolu_01MjNtVJwEcpujRGrf3x6Pih
Args:
query: weather in san francisco
================================= Tool Message =================================
Name: tavily_search_results_json
[{"url": "https://www.wunderground.com/hourly/us/ca/san-francisco/KCASANFR2002/date/2024-6-18", "content": "High 64F. Winds W at 10 to 20 mph. A few clouds from time to time. Low 49F. Winds W at 10 to 20 mph. Temp. San Francisco Weather Forecasts. Weather Underground provides local & long-range weather ..."}]
================================ Human Message =================================
what's the weather in nyc?
================================== Ai Message ==================================
[{'id': 'toolu_01KtE1m1ifPLQAx4fQLyZL9Q', 'input': {'query': 'weather in new york city'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]
Tool Calls:
tavily_search_results_json (toolu_01KtE1m1ifPLQAx4fQLyZL9Q)
Call ID: toolu_01KtE1m1ifPLQAx4fQLyZL9Q
Args:
query: weather in new york city
================================= Tool Message =================================
Name: tavily_search_results_json
[{"url": "https://www.accuweather.com/en/us/new-york/10021/june-weather/349727", "content": "Get the monthly weather forecast for New York, NY, including daily high/low, historical averages, to help you plan ahead."}]
================================== Ai Message ==================================
The search results provide weather forecasts and information for New York City. Based on the top result from AccuWeather, here are some key details about the weather in NYC:
- This is a monthly weather forecast for New York City for the month of June.
- It includes daily high and low temperatures to help plan ahead.
- Historical averages for June in NYC are also provided as a reference point.
- More detailed daily or hourly forecasts with precipitation chances, humidity, wind, etc. can be found by visiting the AccuWeather page.
So in summary, the search provides a convenient overview of the expected weather conditions in New York City over the next month to give you an idea of what to prepare for if traveling or making plans there. Let me know if you need any other details!
Verify that the original, interrupted run was interrupted
=== "Python"
```python
print((await client.runs.get(thread["thread_id"], interrupted_run["run_id"]))["status"])
```
=== "Javascript"
```js
console.log((await client.runs.get(thread['thread_id'], interruptedRun["run_id"]))["status"])
```
Output:
```
'interrupted'
```
+48
View File
@@ -0,0 +1,48 @@
# Run application
!!!info "Prerequisites"
- [Running agents](../../agents/run_agents.md#running-agents)
This guide shows how to submit a [run](../../concepts/assistants.md#execution) to your application.
## Graph mode
### Specify input
First define the input to your graph with in the "Input" section on the left side of the page, below the graph interface.
Studio will attempt to render a form for your input based on the graph's defined [state schema](../../concepts/low_level.md/#schema). To disable this, click the "View Raw" button, which will present you with a JSON editor.
Click the up/down arrows at the top of the "Input" section to toggle through and use previously submitted inputs.
### Run settings
#### Assistant
To specify the [assistant](../../concepts/assistants.md) that is used for the run click the settings button in the bottom left corner. If an assistant is currently selected the button will also list the assistant name. If no assistant is selected it will say "Manage Assistants".
Select the assistant to run and click the "Active" toggle at the top of the modal to activate it. [See here](./studio/manage_assistants.md) for more information on managing assistants.
#### Streaming
Click the dropdown next to "Submit" and click the toggle to enable/disable streaming.
#### Breakpoints
To run your graph with breakpoints, click the "Interrupt" button. Select a node and whether to pause before and/or after that node has executed. Click "Continue" in the thread log to resume execution.
For more information on breakpoints see [here](../../concepts/human_in_the_loop.md).
### Submit run
To submit the run with the specified input and run settings, click the "Submit" button. This will add a [run](../../concepts/assistants.md#execution) to the existing selected [thread](../../concepts/persistence.md#threads). If no thread is currently selected, a new one will be created.
To cancel the ongoing run, click the "Cancel" button.
## Chat mode
Specify the input to your chat application in the bottom of the conversation panel. Click the "Send message" button to submit the input as a Human message and have the response streamed back.
To cancel the ongoing run, click the "Cancel" button. Click the "Show tool calls" toggle to hide/show tool calls in the conversation.
## Learn more
To run your application from a specific checkpoint in an existing thread, see [this guide](./threads_studio.md#edit-thread-history).
@@ -0,0 +1,134 @@
# Iterate on prompts
## Overview
LangGraph Studio supports two methods for modifying prompts in your graph: direct node editing and the LangSmith Playground interface.
## Direct Node Editing
Studio allows you to edit prompts used inside individual nodes, directly from the graph interface.
!!! info "Prerequisites"
- [Assistants overview](../../concepts/assistants.md)
### Graph Configuration
Define your [configuration](https://langchain-ai.github.io/langgraph/how-tos/configuration/) to specify prompt fields and their associated nodes using `langgraph_nodes` and `langgraph_type` keys.
#### Configuration Reference
##### `langgraph_nodes`
- **Description**: Specifies which nodes of the graph a configuration field is associated with.
- **Value Type**: Array of strings, where each string is the name of a node in your graph.
- **Usage Context**: Include in the `json_schema_extra` dictionary for Pydantic models or the `metadata["json_schema_extra"]` dictionary for dataclasses.
- **Example**:
```python
system_prompt: str = Field(
default="You are a helpful AI assistant.",
json_schema_extra={"langgraph_nodes": ["call_model", "other_node"]},
)
```
##### `langgraph_type`
- **Description**: Specifies the type of configuration field, which determines how it's handled in the UI.
- **Value Type**: String
- **Supported Values**:
- `"prompt"`: Indicates the field contains prompt text that should be treated specially in the UI.
- **Usage Context**: Include in the `json_schema_extra` dictionary for Pydantic models or the `metadata["json_schema_extra"]` dictionary for dataclasses.
- **Example**:
```python
system_prompt: str = Field(
default="You are a helpful AI assistant.",
json_schema_extra={
"langgraph_nodes": ["call_model"],
"langgraph_type": "prompt",
},
)
```
#### Example Configuration
```python
## Using Pydantic
from pydantic import BaseModel, Field
from typing import Annotated, Literal
class Configuration(BaseModel):
"""The configuration for the agent."""
system_prompt: str = Field(
default="You are a helpful AI assistant.",
description="The system prompt to use for the agent's interactions. "
"This prompt sets the context and behavior for the agent.",
json_schema_extra={
"langgraph_nodes": ["call_model"],
"langgraph_type": "prompt",
},
)
model: Annotated[
Literal[
"anthropic/claude-3-7-sonnet-latest",
"anthropic/claude-3-5-haiku-latest",
"openai/o1",
"openai/gpt-4o-mini",
"openai/o1-mini",
"openai/o3-mini",
],
{"__template_metadata__": {"kind": "llm"}},
] = Field(
default="openai/gpt-4o-mini",
description="The name of the language model to use for the agent's main interactions. "
"Should be in the form: provider/model-name.",
json_schema_extra={"langgraph_nodes": ["call_model"]},
)
## Using Dataclasses
from dataclasses import dataclass, field
@dataclass(kw_only=True)
class Configuration:
"""The configuration for the agent."""
system_prompt: str = field(
default="You are a helpful AI assistant.",
metadata={
"description": "The system prompt to use for the agent's interactions. "
"This prompt sets the context and behavior for the agent.",
"json_schema_extra": {"langgraph_nodes": ["call_model"]},
},
)
model: Annotated[str, {"__template_metadata__": {"kind": "llm"}}] = field(
default="anthropic/claude-3-5-sonnet-20240620",
metadata={
"description": "The name of the language model to use for the agent's main interactions. "
"Should be in the form: provider/model-name.",
"json_schema_extra": {"langgraph_nodes": ["call_model"]},
},
)
```
### Editing prompts in UI
1. Locate the gear icon on nodes with associated configuration fields
2. Click to open the configuration modal
3. Edit the values
4. Save to update the current assistant version or create a new one
## LangSmith Playground
The [LangSmith Playground](https://
docs.smith.langchain.com/prompt_engineering/how_to_guides#playground) interface allows testing individual LLM calls without running the full graph:
1. Select a thread
2. Click "View LLM Runs" on a node. This lists all the LLM calls (if any) made inside the node.
3. Select an LLM run to open in Playground
4. Modify prompts and test different model and tool settings
5. Copy updated prompts back to your graph
For advanced Playground features, click the expand button in the top right corner.
@@ -0,0 +1,229 @@
# Reject
This guide assumes knowledge of what double-texting is, which you can learn about in the [double-texting conceptual guide](../../concepts/double_texting.md).
The guide covers the `reject` option for double texting, which rejects the new run of the graph by throwing an error and continues with the original run until completion. Below is a quick example of using the `reject` option.
## Setup
First, we will define a quick helper function for printing out JS and CURL model outputs (you can skip this if using Python):
=== "Javascript"
```js
function prettyPrint(m) {
const padded = " " + m['type'] + " ";
const sepLen = Math.floor((80 - padded.length) / 2);
const sep = "=".repeat(sepLen);
const secondSep = sep + (padded.length % 2 ? "=" : "");
console.log(`${sep}${padded}${secondSep}`);
console.log("\n\n");
console.log(m.content);
}
```
=== "CURL"
```bash
# PLACE THIS IN A FILE CALLED pretty_print.sh
pretty_print() {
local type="$1"
local content="$2"
local padded=" $type "
local total_width=80
local sep_len=$(( (total_width - ${#padded}) / 2 ))
local sep=$(printf '=%.0s' $(eval "echo {1.."${sep_len}"}"))
local second_sep=$sep
if (( (total_width - ${#padded}) % 2 )); then
second_sep="${second_sep}="
fi
echo "${sep}${padded}${second_sep}"
echo
echo "$content"
}
```
Now, let's import our required packages and instantiate our client, assistant, and thread.
=== "Python"
```python
import httpx
from langchain_core.messages import convert_to_messages
from langgraph_sdk import get_client
client = get_client(url=<DEPLOYMENT_URL>)
# Using the graph deployed with the name "agent"
assistant_id = "agent"
thread = await client.threads.create()
```
=== "Javascript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });
// Using the graph deployed with the name "agent"
const assistantId = "agent";
const thread = await client.threads.create();
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}'
```
## Create runs
Now we can run a thread and try to run a second one with the "reject" option, which should fail since we have already started a run:
=== "Python"
```python
run = await client.runs.create(
thread["thread_id"],
assistant_id,
input={"messages": [{"role": "user", "content": "what's the weather in sf?"}]},
)
try:
await client.runs.create(
thread["thread_id"],
assistant_id,
input={
"messages": [{"role": "user", "content": "what's the weather in nyc?"}]
},
multitask_strategy="reject",
)
except httpx.HTTPStatusError as e:
print("Failed to start concurrent run", e)
```
=== "Javascript"
```js
const run = await client.runs.create(
thread["thread_id"],
assistantId,
input={"messages": [{"role": "user", "content": "what's the weather in sf?"}]},
);
try {
await client.runs.create(
thread["thread_id"],
assistantId,
{
input: {"messages": [{"role": "user", "content": "what's the weather in nyc?"}]},
multitask_strategy:"reject"
},
);
} catch (e) {
console.error("Failed to start concurrent run", e);
}
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOY<ENT_URL>>/threads/<THREAD_ID>/runs \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {\"messages\": [{\"role\": \"human\", \"content\": \"what\'s the weather in sf?\"}]},
}" && curl --request POST \
--url <DEPLOY<ENT_URL>>/threads/<THREAD_ID>/runs \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {\"messages\": [{\"role\": \"human\", \"content\": \"what\'s the weather in nyc?\"}]},
\"multitask_strategy\": \"reject\"
}" || { echo "Failed to start concurrent run"; echo "Error: $?" >&2; }
```
Output:
Failed to start concurrent run Client error '409 Conflict' for url 'http://localhost:8123/threads/f9e7088b-8028-4e5c-88d2-9cc9a2870e50/runs'
For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/409
## View run results
We can verify that the original thread finished executing:
=== "Python"
```python
# wait until the original run completes
await client.runs.join(thread["thread_id"], run["run_id"])
state = await client.threads.get_state(thread["thread_id"])
for m in convert_to_messages(state["values"]["messages"]):
m.pretty_print()
```
=== "Javascript"
```js
await client.runs.join(thread["thread_id"], run["run_id"]);
const state = await client.threads.getState(thread["thread_id"]);
for (const m of state["values"]["messages"]) {
prettyPrint(m);
}
```
=== "CURL"
```bash
source pretty_print.sh && curl --request GET \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/<RUN_ID>/join && \
curl --request GET --url <DEPLOYMENT_URL>/threads/<THREAD_ID>/state | \
jq -c '.values.messages[]' | while read -r element; do
type=$(echo "$element" | jq -r '.type')
content=$(echo "$element" | jq -r '.content | if type == "array" then tostring else . end')
pretty_print "$type" "$content"
done
```
Output:
================================ Human Message =================================
what's the weather in sf?
================================== Ai Message ==================================
[{'id': 'toolu_01CyewEifV2Kmi7EFKHbMDr1', 'input': {'query': 'weather in san francisco'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]
Tool Calls:
tavily_search_results_json (toolu_01CyewEifV2Kmi7EFKHbMDr1)
Call ID: toolu_01CyewEifV2Kmi7EFKHbMDr1
Args:
query: weather in san francisco
================================= Tool Message =================================
Name: tavily_search_results_json
[{"url": "https://www.accuweather.com/en/us/san-francisco/94103/june-weather/347629", "content": "Get the monthly weather forecast for San Francisco, CA, including daily high/low, historical averages, to help you plan ahead."}]
================================== Ai Message ==================================
According to the search results from Tavily, the current weather in San Francisco is:
The average high temperature in San Francisco in June is around 65°F (18°C), with average lows around 54°F (12°C). June tends to be one of the cooler and foggier months in San Francisco due to the marine layer of fog that often blankets the city during the summer months.
Some key points about the typical June weather in San Francisco:
- Mild temperatures with highs in the 60s F and lows in the 50s F
- Foggy mornings that often burn off to sunny afternoons
- Little to no rainfall, as June falls in the dry season
- Breezy conditions, with winds off the Pacific Ocean
- Layers are recommended for changing weather conditions
So in summary, you can expect mild, foggy mornings giving way to sunny but cool afternoons in San Francisco this time of year. The marine layer keeps temperatures moderate compared to other parts of California in June.
@@ -0,0 +1,233 @@
# How to use the Rollback option
This guide assumes knowledge of what double-texting is, which you can learn about in the [double-texting conceptual guide](../../concepts/double_texting.md).
The guide covers the `rollback` option for double texting, which interrupts the prior run of the graph and starts a new one with the double-text. This option is very similar to the `interrupt` option, but in this case the first run is completely deleted from the database and cannot be restarted. Below is a quick example of using the `rollback` option.
## Setup
First, we will define a quick helper function for printing out JS and CURL model outputs (you can skip this if using Python):
=== "Javascript"
```js
function prettyPrint(m) {
const padded = " " + m['type'] + " ";
const sepLen = Math.floor((80 - padded.length) / 2);
const sep = "=".repeat(sepLen);
const secondSep = sep + (padded.length % 2 ? "=" : "");
console.log(`${sep}${padded}${secondSep}`);
console.log("\n\n");
console.log(m.content);
}
```
=== "CURL"
```bash
# PLACE THIS IN A FILE CALLED pretty_print.sh
pretty_print() {
local type="$1"
local content="$2"
local padded=" $type "
local total_width=80
local sep_len=$(( (total_width - ${#padded}) / 2 ))
local sep=$(printf '=%.0s' $(eval "echo {1.."${sep_len}"}"))
local second_sep=$sep
if (( (total_width - ${#padded}) % 2 )); then
second_sep="${second_sep}="
fi
echo "${sep}${padded}${second_sep}"
echo
echo "$content"
}
```
Now, let's import our required packages and instantiate our client, assistant, and thread.
=== "Python"
```python
import asyncio
import httpx
from langchain_core.messages import convert_to_messages
from langgraph_sdk import get_client
client = get_client(url=<DEPLOYMENT_URL>)
# Using the graph deployed with the name "agent"
assistant_id = "agent"
thread = await client.threads.create()
```
=== "Javascript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });
// Using the graph deployed with the name "agent"
const assistantId = "agent";
const thread = await client.threads.create();
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}'
```
## Create runs
Now let's run a thread with the multitask parameter set to "rollback":
=== "Python"
```python
# the first run will be rolled back
rolled_back_run = await client.runs.create(
thread["thread_id"],
assistant_id,
input={"messages": [{"role": "user", "content": "what's the weather in sf?"}]},
)
run = await client.runs.create(
thread["thread_id"],
assistant_id,
input={"messages": [{"role": "user", "content": "what's the weather in nyc?"}]},
multitask_strategy="rollback",
)
# wait until the second run completes
await client.runs.join(thread["thread_id"], run["run_id"])
```
=== "Javascript"
```js
// the first run will be interrupted
let rolledBackRun = await client.runs.create(
thread["thread_id"],
assistantId,
{ input: { messages: [{ role: "human", content: "what's the weather in sf?" }] } }
);
let run = await client.runs.create(
thread["thread_id"],
assistant_id,
{
input: { messages: [{ role: "human", content: "what's the weather in nyc?" }] },
multitaskStrategy: "rollback"
}
);
// wait until the second run completes
await client.runs.join(thread["thread_id"], run["run_id"]);
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOY<ENT_URL>>/threads/<THREAD_ID>/runs \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {\"messages\": [{\"role\": \"human\", \"content\": \"what\'s the weather in sf?\"}]},
}" && curl --request POST \
--url <DEPLOY<ENT_URL>>/threads/<THREAD_ID>/runs \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {\"messages\": [{\"role\": \"human\", \"content\": \"what\'s the weather in nyc?\"}]},
\"multitask_strategy\": \"rollback\"
}" && curl --request GET \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/<RUN_ID>/join
```
## View run results
We can see that the thread has data only from the second run
=== "Python"
```python
state = await client.threads.get_state(thread["thread_id"])
for m in convert_to_messages(state["values"]["messages"]):
m.pretty_print()
```
=== "Javascript"
```js
const state = await client.threads.getState(thread["thread_id"]);
for (const m of state['values']['messages']) {
prettyPrint(m);
}
```
=== "CURL"
```bash
source pretty_print.sh && curl --request GET \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/state | \
jq -c '.values.messages[]' | while read -r element; do
type=$(echo "$element" | jq -r '.type')
content=$(echo "$element" | jq -r '.content | if type == "array" then tostring else . end')
pretty_print "$type" "$content"
done
```
Output:
================================ Human Message =================================
what's the weather in nyc?
================================== Ai Message ==================================
[{'id': 'toolu_01JzPqefao1gxwajHQ3Yh3JD', 'input': {'query': 'weather in nyc'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]
Tool Calls:
tavily_search_results_json (toolu_01JzPqefao1gxwajHQ3Yh3JD)
Call ID: toolu_01JzPqefao1gxwajHQ3Yh3JD
Args:
query: weather in nyc
================================= Tool Message =================================
Name: tavily_search_results_json
[{"url": "https://www.weatherapi.com/", "content": "{'location': {'name': 'New York', 'region': 'New York', 'country': 'United States of America', 'lat': 40.71, 'lon': -74.01, 'tz_id': 'America/New_York', 'localtime_epoch': 1718734479, 'localtime': '2024-06-18 14:14'}, 'current': {'last_updated_epoch': 1718733600, 'last_updated': '2024-06-18 14:00', 'temp_c': 29.4, 'temp_f': 84.9, 'is_day': 1, 'condition': {'text': 'Sunny', 'icon': '//cdn.weatherapi.com/weather/64x64/day/113.png', 'code': 1000}, 'wind_mph': 2.2, 'wind_kph': 3.6, 'wind_degree': 158, 'wind_dir': 'SSE', 'pressure_mb': 1025.0, 'pressure_in': 30.26, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 63, 'cloud': 0, 'feelslike_c': 31.3, 'feelslike_f': 88.3, 'windchill_c': 28.3, 'windchill_f': 82.9, 'heatindex_c': 29.6, 'heatindex_f': 85.3, 'dewpoint_c': 18.4, 'dewpoint_f': 65.2, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 7.0, 'gust_mph': 16.5, 'gust_kph': 26.5}}"}]
================================== Ai Message ==================================
The weather API results show that the current weather in New York City is sunny with a temperature of around 85°F (29°C). The wind is light at around 2-3 mph from the south-southeast. Overall it looks like a nice sunny summer day in NYC.
Verify that the original, rolled back run was deleted
=== "Python"
```python
try:
await client.runs.get(thread["thread_id"], rolled_back_run["run_id"])
except httpx.HTTPStatusError as _:
print("Original run was correctly deleted")
```
=== "Javascript"
```js
try {
await client.runs.get(thread["thread_id"], rolledBackRun["run_id"]);
} catch (e) {
console.log("Original run was correctly deleted");
}
```
Output:
Original run was correctly deleted
+318
View File
@@ -0,0 +1,318 @@
# How to run multiple agents on the same thread
In LangGraph Platform, a thread is not explicitly associated with a particular agent.
This means that you can run multiple agents on the same thread, which allows a different agent to continue from an initial agent's progress.
In this example, we will create two agents and then call them both on the same thread.
You'll see that the second agent will respond using information from the [checkpoint](https://langchain-ai.github.io/langgraph/concepts/low_level/#checkpointer-state) generated in the thread by the first agent as context.
## Setup
=== "Python"
```python
from langgraph_sdk import get_client
client = get_client(url=<DEPLOYMENT_URL>)
openai_assistant = await client.assistants.create(
graph_id="agent", config={"configurable": {"model_name": "openai"}}
)
# There should always be a default assistant with no configuration
assistants = await client.assistants.search()
default_assistant = [a for a in assistants if not a["config"]][0]
```
=== "Javascript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });
const openAIAssistant = await client.assistants.create(
{ graphId: "agent", config: {"configurable": {"model_name": "openai"}}}
);
const assistants = await client.assistants.search();
const defaultAssistant = assistants.find(a => !a.config);
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/assistants \
--header 'Content-Type: application/json' \
--data '{
"graph_id": "agent",
"config": { "configurable": { "model_name": "openai" } }
}' && \
curl --request POST \
--url <DEPLOYMENT_URL>/assistants/search \
--header 'Content-Type: application/json' \
--data '{
"limit": 10,
"offset": 0
}' | jq -c 'map(select(.config == null or .config == {})) | .[0]'
```
We can see that these agents are different:
=== "Python"
```python
print(openai_assistant)
```
=== "Javascript"
```js
console.log(openAIAssistant);
```
=== "CURL"
```bash
curl --request GET \
--url <DEPLOYMENT_URL>/assistants/<OPENAI_ASSISTANT_ID>
```
Output:
{
"assistant_id": "db87f39d-b2b1-4da8-ac65-cf81beb3c766",
"graph_id": "agent",
"created_at": "2024-08-30T21:18:51.850581+00:00",
"updated_at": "2024-08-30T21:18:51.850581+00:00",
"config": {
"configurable": {
"model_name": "openai"
}
},
"metadata": {}
}
=== "Python"
```python
print(default_assistant)
```
=== "Javascript"
```js
console.log(defaultAssistant);
```
=== "CURL"
```bash
curl --request GET \
--url <DEPLOYMENT_URL>/assistants/<DEFAULT_ASSISTANT_ID>
```
Output:
{
"assistant_id": "fe096781-5601-53d2-b2f6-0d3403f7e9ca",
"graph_id": "agent",
"created_at": "2024-08-08T22:45:24.562906+00:00",
"updated_at": "2024-08-08T22:45:24.562906+00:00",
"config": {},
"metadata": {
"created_by": "system"
}
}
## Run assistants on thread
### Run OpenAI assistant
We can now run the OpenAI assistant on the thread first.
=== "Python"
```python
thread = await client.threads.create()
input = {"messages": [{"role": "user", "content": "who made you?"}]}
async for event in client.runs.stream(
thread["thread_id"],
openai_assistant["assistant_id"],
input=input,
stream_mode="updates",
):
print(f"Receiving event of type: {event.event}")
print(event.data)
print("\n\n")
```
=== "Javascript"
```js
const thread = await client.threads.create();
let input = {"messages": [{"role": "user", "content": "who made you?"}]}
const streamResponse = client.runs.stream(
thread["thread_id"],
openAIAssistant["assistant_id"],
{
input,
streamMode: "updates"
}
);
for await (const event of streamResponse) {
console.log(`Receiving event of type: ${event.event}`);
console.log(event.data);
console.log("\n\n");
}
```
=== "CURL"
```bash
thread_id=$(curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}' | jq -r '.thread_id') && \
curl --request POST \
--url "<DEPLOYMENT_URL>/threads/${thread_id}/runs/stream" \
--header 'Content-Type: application/json' \
--data '{
"assistant_id": <OPENAI_ASSISTANT_ID>,
"input": {
"messages": [
{
"role": "user",
"content": "who made you?"
}
]
},
"stream_mode": [
"updates"
]
}' | \
sed 's/\r$//' | \
awk '
/^event:/ {
if (data_content != "") {
print data_content "\n"
}
sub(/^event: /, "Receiving event of type: ", $0)
printf "%s...\n", $0
data_content = ""
}
/^data:/ {
sub(/^data: /, "", $0)
data_content = $0
}
END {
if (data_content != "") {
print data_content "\n\n"
}
}
'
```
Output:
Receiving event of type: metadata
{'run_id': '1ef671c5-fb83-6e70-b698-44dba2d9213e'}
Receiving event of type: updates
{'agent': {'messages': [{'content': 'I was created by OpenAI, a research organization focused on developing and advancing artificial intelligence technology.', 'additional_kwargs': {}, 'response_metadata': {'finish_reason': 'stop', 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_157b3831f5'}, 'type': 'ai', 'name': None, 'id': 'run-f5735b86-b80d-4c71-8dc3-4782b5a9c7c8', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]}}
### Run default assistant
Now, we can run it on the default assistant and see that this second assistant is aware of the initial question, and can answer the question, "and you?":
=== "Python"
```python
input = {"messages": [{"role": "user", "content": "and you?"}]}
async for event in client.runs.stream(
thread["thread_id"],
default_assistant["assistant_id"],
input=input,
stream_mode="updates",
):
print(f"Receiving event of type: {event.event}")
print(event.data)
print("\n\n")
```
=== "Javascript"
```js
let input = {"messages": [{"role": "user", "content": "and you?"}]}
const streamResponse = client.runs.stream(
thread["thread_id"],
defaultAssistant["assistant_id"],
{
input,
streamMode: "updates"
}
);
for await (const event of streamResponse) {
console.log(`Receiving event of type: ${event.event}`);
console.log(event.data);
console.log("\n\n");
}
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/stream \
--header 'Content-Type: application/json' \
--data '{
"assistant_id": <DEFAULT_ASSISTANT_ID>,
"input": {
"messages": [
{
"role": "user",
"content": "and you?"
}
]
},
"stream_mode": [
"updates"
]
}' | \
sed 's/\r$//' | \
awk '
/^event:/ {
if (data_content != "") {
print data_content "\n"
}
sub(/^event: /, "Receiving event of type: ", $0)
printf "%s...\n", $0
data_content = ""
}
/^data:/ {
sub(/^data: /, "", $0)
data_content = $0
}
END {
if (data_content != "") {
print data_content "\n\n"
}
}
'
```
Output:
Receiving event of type: metadata
{'run_id': '1ef6722d-80b3-6fbb-9324-253796b1cd13'}
Receiving event of type: updates
{'agent': {'messages': [{'content': [{'text': 'I am an artificial intelligence created by Anthropic, not by OpenAI. I should not have stated that OpenAI created me, as that is incorrect. Anthropic is the company that developed and trained me using advanced language models and AI technology. I will be more careful about providing accurate information regarding my origins in the future.', 'type': 'text', 'index': 0}], 'additional_kwargs': {}, 'response_metadata': {'stop_reason': 'end_turn', 'stop_sequence': None}, 'type': 'ai', 'name': None, 'id': 'run-ebaacf62-9dd9-4165-9535-db432e4793ec', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': {'input_tokens': 302, 'output_tokens': 72, 'total_tokens': 374}}]}}
+180
View File
@@ -0,0 +1,180 @@
# Stateless Runs
Most of the time, you provide a `thread_id` to your client when you run your graph in order to keep track of prior runs through the persistent state implemented in LangGraph Platform. However, if you don't need to persist the runs you don't need to use the built in persistent state and can create stateless runs.
## Setup
First, let's setup our client:
=== "Python"
```python
from langgraph_sdk import get_client
client = get_client(url=<DEPLOYMENT_URL>)
# Using the graph deployed with the name "agent"
assistant_id = "agent"
# create thread
thread = await client.threads.create()
```
=== "Javascript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });
// Using the graph deployed with the name "agent"
const assistantId = "agent";
// create thread
const thread = await client.threads.create();
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/assistants/search \
--header 'Content-Type: application/json' \
--data '{
"limit": 10,
"offset": 0
}' | jq -c 'map(select(.config == null or .config == {})) | .[0].graph_id' && \
curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}'
```
## Stateless streaming
We can stream the results of a stateless run in an almost identical fashion to how we stream from a run with the state attribute, but instead of passing a value to the `thread_id` parameter, we pass `None`:
=== "Python"
```python
input = {
"messages": [
{"role": "user", "content": "Hello! My name is Bagatur and I am 26 years old."}
]
}
async for chunk in client.runs.stream(
# Don't pass in a thread_id and the stream will be stateless
None,
assistant_id,
input=input,
stream_mode="updates",
):
if chunk.data and "run_id" not in chunk.data:
print(chunk.data)
```
=== "Javascript"
```js
let input = {
messages: [
{ role: "user", content: "Hello! My name is Bagatur and I am 26 years old." }
]
};
const streamResponse = client.runs.stream(
// Don't pass in a thread_id and the stream will be stateless
null,
assistantId,
{
input,
streamMode: "updates"
}
);
for await (const chunk of streamResponse) {
if (chunk.data && !("run_id" in chunk.data)) {
console.log(chunk.data);
}
}
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/runs/stream \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {\"messages\": [{\"role\": \"human\", \"content\": \"Hello! My name is Bagatur and I am 26 years old.\"}]},
\"stream_mode\": [
\"updates\"
]
}" | jq -c 'select(.data and (.data | has("run_id") | not)) | .data'
```
Output:
{'agent': {'messages': [{'content': "Hello Bagatur! It's nice to meet you. Thank you for introducing yourself and sharing your age. Is there anything specific you'd like to know or discuss? I'm here to help with any questions or topics you're interested in.", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-489ec573-1645-4ce2-a3b8-91b391d50a71', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]}}
## Waiting for stateless results
In addition to streaming, you can also wait for a stateless result by using the `.wait` function like follows:
=== "Python"
```python
stateless_run_result = await client.runs.wait(
None,
assistant_id,
input=input,
)
print(stateless_run_result)
```
=== "Javascript"
```js
let statelessRunResult = await client.runs.wait(
null,
assistantId,
{ input: input }
);
console.log(statelessRunResult);
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/runs/wait \
--header 'Content-Type: application/json' \
--data '{
"assistant_id": <ASSISTANT_IDD>,
}'
```
Output:
{
'messages': [
{
'content': 'Hello! My name is Bagatur and I am 26 years old.',
'additional_kwargs': {},
'response_metadata': {},
'type': 'human',
'name': None,
'id': '5e088543-62c2-43de-9d95-6086ad7f8b48',
'example': False}
,
{
'content': "Hello Bagatur! It's nice to meet you. Thank you for introducing yourself and sharing your age. Is there anything specific you'd like to know or discuss? I'm here to help with any questions or topics you'd like to explore.",
'additional_kwargs': {},
'response_metadata': {},
'type': 'ai',
'name': None,
'id': 'run-d6361e8d-4d4c-45bd-ba47-39520257f773',
'example': False,
'tool_calls': [],
'invalid_tool_calls': [],
'usage_metadata': None
}
]
}
+957
View File
@@ -0,0 +1,957 @@
# Streaming API
[LangGraph SDK](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/) allows you to [stream outputs](../../concepts/streaming.md) from the LangGraph API server.
!!! note
LangGraph SDK and LangGraph Server are a part of [LangGraph Platform](../../concepts/langgraph_platform.md).
## Basic usage
Basic usage example:
=== "Python"
```python
from langgraph_sdk import get_client
client = get_client(url=<DEPLOYMENT_URL>, api_key=<API_KEY>)
# Using the graph deployed with the name "agent"
assistant_id = "agent"
# create a thread
thread = await client.threads.create()
thread_id = thread["thread_id"]
# create a streaming run
# highlight-next-line
async for chunk in client.runs.stream(
thread_id,
assistant_id,
input=inputs,
stream_mode="updates"
):
print(chunk.data)
```
=== "JavaScript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL>, apiKey: <API_KEY> });
// Using the graph deployed with the name "agent"
const assistantID = "agent";
// create a thread
const thread = await client.threads.create();
const threadID = thread["thread_id"];
// create a streaming run
// highlight-next-line
const streamResponse = client.runs.stream(
threadID,
assistantID,
{
input,
streamMode: "updates"
}
);
for await (const chunk of streamResponse) {
console.log(chunk.data);
}
```
=== "cURL"
Create a thread:
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}'
```
Create a streaming run:
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/stream \
--header 'Content-Type: application/json' \
--header 'x-api-key: <API_KEY>'
--data "{
\"assistant_id\": \"agent\",
\"input\": <inputs>,
\"stream_mode\": \"updates\"
}"
```
??? example "Extended example: streaming updates"
This is an example graph you can run in the LangGraph API server.
See [LangGraph Platform quickstart](../quick_start.md) for more details.
```python
# graph.py
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
class State(TypedDict):
topic: str
joke: str
def refine_topic(state: State):
return {"topic": state["topic"] + " and cats"}
def generate_joke(state: State):
return {"joke": f"This is a joke about {state['topic']}"}
graph = (
StateGraph(State)
.add_node(refine_topic)
.add_node(generate_joke)
.add_edge(START, "refine_topic")
.add_edge("refine_topic", "generate_joke")
.add_edge("generate_joke", END)
.compile()
)
```
Once you have a running LangGraph API server, you can interact with it using
[LangGraph SDK](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/)
=== "Python"
```python
from langgraph_sdk import get_client
client = get_client(url=<DEPLOYMENT_URL>)
# Using the graph deployed with the name "agent"
assistant_id = "agent"
# create a thread
thread = await client.threads.create()
thread_id = thread["thread_id"]
# create a streaming run
# highlight-next-line
async for chunk in client.runs.stream( # (1)!
thread_id,
assistant_id,
input={"topic": "ice cream"},
# highlight-next-line
stream_mode="updates" # (2)!
):
print(chunk.data)
```
1. The `client.runs.stream()` method returns an iterator that yields streamed outputs.
2. Set `stream_mode="updates"` to stream only the updates to the graph state after each node. Other stream modes are also available. See [supported stream modes](#supported-stream-modes) for details.
=== "JavaScript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });
// Using the graph deployed with the name "agent"
const assistantID = "agent";
// create a thread
const thread = await client.threads.create();
const threadID = thread["thread_id"];
// create a streaming run
// highlight-next-line
const streamResponse = client.runs.stream( // (1)!
threadID,
assistantID,
{
input: { topic: "ice cream" },
// highlight-next-line
streamMode: "updates" // (2)!
}
);
for await (const chunk of streamResponse) {
console.log(chunk.data);
}
```
1. The `client.runs.stream()` method returns an iterator that yields streamed outputs.
2. Set `streamMode: "updates"` to stream only the updates to the graph state after each node. Other stream modes are also available. See [supported stream modes](#supported-stream-modes) for details.
=== "cURL"
Create a thread:
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}'
```
Create a streaming run:
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/stream \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {\"topic\": \"ice cream\"},
\"stream_mode\": \"updates\"
}"
```
```output
{'run_id': '1f02c2b3-3cef-68de-b720-eec2a4a8e920', 'attempt': 1}
{'refine_topic': {'topic': 'ice cream and cats'}}
{'generate_joke': {'joke': 'This is a joke about ice cream and cats'}}
```
### Supported stream modes
| Mode | Description | LangGraph Library Method |
|----------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------|
| [`values`](#stream-graph-state) | Stream the full graph state after each [super-step](../../concepts/low_level.md#graphs). | `.stream()` / `.astream()` with [`stream_mode="values"`](../../how-tos/streaming.md#stream-graph-state) |
| [`updates`](#stream-graph-state) | Streams the updates to the state after each step of the graph. If multiple updates are made in the same step (e.g., multiple nodes are run), those updates are streamed separately. | `.stream()` / `.astream()` with [`stream_mode="updates"`](../../how-tos/streaming.md#stream-graph-state) |
| [`messages-tuple`](#messages) | Streams LLM tokens and metadata for the graph node where the LLM is invoked (useful for chat apps). | `.stream()` / `.astream()` with [`stream_mode="messages"`](../../how-tos/streaming.md#messages) |
| [`debug`](#debug) | Streams as much information as possible throughout the execution of the graph. | `.stream()` / `.astream()` with [`stream_mode="debug"`](../../how-tos/streaming.md#stream-graph-state) |
| [`custom`](#stream-custom-data) | Streams custom data from inside your graph | `.stream()` / `.astream()` with [`stream_mode="custom"`](../../how-tos/streaming.md#stream-custom-data) |
| [`events`](#stream-events) | Stream all events (including the state of the graph); mainly useful when migrating large LCEL apps. | `.astream_events()` |
### Stream multiple modes
You can pass a list as the `stream_mode` parameter to stream multiple modes at once.
The streamed outputs will be tuples of `(mode, chunk)` where `mode` is the name of the stream mode and `chunk` is the data streamed by that mode.
=== "Python"
```python
async for chunk in client.runs.stream(
thread_id,
assistant_id,
input=inputs,
stream_mode=["updates", "custom"]
):
print(chunk)
```
=== "JavaScript"
```js
const streamResponse = client.runs.stream(
threadID,
assistantID,
{
input,
streamMode: ["updates", "custom"]
}
);
for await (const chunk of streamResponse) {
console.log(chunk);
}
```
=== "cURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/stream \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": <inputs>,
\"stream_mode\": [
\"updates\"
\"custom\"
]
}"
```
## Stream graph state
Use the stream modes `updates` and `values` to stream the state of the graph as it executes.
* `updates` streams the **updates** to the state after each step of the graph.
* `values` streams the **full value** of the state after each step of the graph.
??? example "Example graph"
```python
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
class State(TypedDict):
topic: str
joke: str
def refine_topic(state: State):
return {"topic": state["topic"] + " and cats"}
def generate_joke(state: State):
return {"joke": f"This is a joke about {state['topic']}"}
graph = (
StateGraph(State)
.add_node(refine_topic)
.add_node(generate_joke)
.add_edge(START, "refine_topic")
.add_edge("refine_topic", "generate_joke")
.add_edge("generate_joke", END)
.compile()
)
```
!!! note "Stateful runs"
Examples below assume that you want to **persist the outputs** of a streaming run in the [checkpointer](../../concepts/persistence.md) DB and have created a thread. To create a thread:
=== "Python"
```python
from langgraph_sdk import get_client
client = get_client(url=<DEPLOYMENT_URL>)
# Using the graph deployed with the name "agent"
assistant_id = "agent"
# create a thread
thread = await client.threads.create()
thread_id = thread["thread_id"]
```
=== "JavaScript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });
// Using the graph deployed with the name "agent"
const assistantID = "agent";
// create a thread
const thread = await client.threads.create();
const threadID = thread["thread_id"]
```
=== "cURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}'
```
If you don't need to persist the outputs of a run, you can pass `None` instead of `thread_id` when streaming.
=== "updates"
Use this to stream only the **state updates** returned by the nodes after each step. The streamed outputs include the name of the node as well as the update.
=== "Python"
```python
async for chunk in client.runs.stream(
thread_id,
assistant_id,
input={"topic": "ice cream"},
# highlight-next-line
stream_mode="updates"
):
print(chunk.data)
```
=== "JavaScript"
```js
const streamResponse = client.runs.stream(
threadID,
assistantID,
{
input: { topic: "ice cream" },
// highlight-next-line
streamMode: "updates"
}
);
for await (const chunk of streamResponse) {
console.log(chunk.data);
}
```
=== "cURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/stream \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {\"topic\": \"ice cream\"},
\"stream_mode\": \"updates\"
}"
```
=== "values"
Use this to stream the **full state** of the graph after each step.
=== "Python"
```python
async for chunk in client.runs.stream(
thread_id,
assistant_id,
input={"topic": "ice cream"},
# highlight-next-line
stream_mode="values"
):
print(chunk.data)
```
=== "JavaScript"
```js
const streamResponse = client.runs.stream(
threadID,
assistantID,
{
input: { topic: "ice cream" },
// highlight-next-line
streamMode: "values"
}
);
for await (const chunk of streamResponse) {
console.log(chunk.data);
}
```
=== "cURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/stream \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {\"topic\": \"ice cream\"},
\"stream_mode\": \"values\"
}"
```
## Subgraphs
To include outputs from [subgraphs](../../concepts/subgraphs.md) in the streamed outputs, you can set `subgraphs=True` in the `.stream()` method of the parent graph. This will stream outputs from both the parent graph and any subgraphs.
```python
for chunk in client.runs.stream(
thread_id,
assistant_id,
input={"foo": "foo"},
# highlight-next-line
stream_subgraphs=True, # (1)!
stream_mode="updates",
):
print(chunk)
```
1. Set `stream_subgraphs=True` to stream outputs from subgraphs.
??? example "Extended example: streaming from subgraphs"
This is an example graph you can run in the LangGraph API server.
See [LangGraph Platform quickstart](../quick_start.md) for more details.
```python
# graph.py
from langgraph.graph import START, StateGraph
from typing import TypedDict
# Define subgraph
class SubgraphState(TypedDict):
foo: str # note that this key is shared with the parent graph state
bar: str
def subgraph_node_1(state: SubgraphState):
return {"bar": "bar"}
def subgraph_node_2(state: SubgraphState):
return {"foo": state["foo"] + state["bar"]}
subgraph_builder = StateGraph(SubgraphState)
subgraph_builder.add_node(subgraph_node_1)
subgraph_builder.add_node(subgraph_node_2)
subgraph_builder.add_edge(START, "subgraph_node_1")
subgraph_builder.add_edge("subgraph_node_1", "subgraph_node_2")
subgraph = subgraph_builder.compile()
# Define parent graph
class ParentState(TypedDict):
foo: str
def node_1(state: ParentState):
return {"foo": "hi! " + state["foo"]}
builder = StateGraph(ParentState)
builder.add_node("node_1", node_1)
builder.add_node("node_2", subgraph)
builder.add_edge(START, "node_1")
builder.add_edge("node_1", "node_2")
graph = builder.compile()
```
Once you have a running LangGraph API server, you can interact with it using
[LangGraph SDK](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/)
=== "Python"
```python
from langgraph_sdk import get_client
client = get_client(url=<DEPLOYMENT_URL>)
# Using the graph deployed with the name "agent"
assistant_id = "agent"
# create a thread
thread = await client.threads.create()
thread_id = thread["thread_id"]
async for chunk in client.runs.stream(
thread_id,
assistant_id,
input={"foo": "foo"},
# highlight-next-line
stream_subgraphs=True, # (1)!
stream_mode="updates",
):
print(chunk)
```
1. Set `stream_subgraphs=True` to stream outputs from subgraphs.
=== "JavaScript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });
// Using the graph deployed with the name "agent"
const assistantID = "agent";
// create a thread
const thread = await client.threads.create();
const threadID = thread["thread_id"];
// create a streaming run
const streamResponse = client.runs.stream(
threadID,
assistantID,
{
input: { foo: "foo" },
// highlight-next-line
streamSubgraphs: true, // (1)!
streamMode: "updates"
}
);
for await (const chunk of streamResponse) {
console.log(chunk);
}
```
1. Set `streamSubgraphs: true` to stream outputs from subgraphs.
=== "cURL"
Create a thread:
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}'
```
Create a streaming run:
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/stream \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {\"foo\": \"foo\"},
\"stream_subgraphs\": true,
\"stream_mode\": [
\"updates\"
]
}"
```
**Note** that we are receiving not just the node updates, but we also the namespaces which tell us what graph (or subgraph) we are streaming from.
## Debugging {#debug}
Use the `debug` streaming mode to stream as much information as possible throughout the execution of the graph. The streamed outputs include the name of the node as well as the full state.
=== "Python"
```python
async for chunk in client.runs.stream(
thread_id,
assistant_id,
input={"topic": "ice cream"},
# highlight-next-line
stream_mode="debug"
):
print(chunk.data)
```
=== "JavaScript"
```js
const streamResponse = client.runs.stream(
threadID,
assistantID,
{
input: { topic: "ice cream" },
// highlight-next-line
streamMode: "debug"
}
);
for await (const chunk of streamResponse) {
console.log(chunk.data);
}
```
=== "cURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/stream \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {\"topic\": \"ice cream\"},
\"stream_mode\": \"debug\"
}"
```
## LLM tokens {#messages}
Use the `messages-tuple` streaming mode to stream Large Language Model (LLM) outputs **token by token** from any part of your graph, including nodes, tools, subgraphs, or tasks.
The streamed output from [`messages-tuple` mode](#supported-stream-modes) is a tuple `(message_chunk, metadata)` where:
- `message_chunk`: the token or message segment from the LLM.
- `metadata`: a dictionary containing details about the graph node and LLM invocation.
??? example "Example graph"
```python
from dataclasses import dataclass
from langchain.chat_models import init_chat_model
from langgraph.graph import StateGraph, START
@dataclass
class MyState:
topic: str
joke: str = ""
llm = init_chat_model(model="openai:gpt-4o-mini")
def call_model(state: MyState):
"""Call the LLM to generate a joke about a topic"""
# highlight-next-line
llm_response = llm.invoke( # (1)!
[
{"role": "user", "content": f"Generate a joke about {state.topic}"}
]
)
return {"joke": llm_response.content}
graph = (
StateGraph(MyState)
.add_node(call_model)
.add_edge(START, "call_model")
.compile()
)
```
1. Note that the message events are emitted even when the LLM is run using `.invoke` rather than `.stream`.
=== "Python"
```python
async for chunk in client.runs.stream(
thread_id,
assistant_id,
input={"topic": "ice cream"},
# highlight-next-line
stream_mode="messages-tuple",
):
if chunk.event != "messages":
continue
message_chunk, metadata = chunk.data # (1)!
if message_chunk["content"]:
print(message_chunk["content"], end="|", flush=True)
```
1. The "messages-tuple" stream mode returns an iterator of tuples `(message_chunk, metadata)` where `message_chunk` is the token streamed by the LLM and `metadata` is a dictionary with information about the graph node where the LLM was called and other information.
=== "JavaScript"
```js
const streamResponse = client.runs.stream(
threadID,
assistantID,
{
input: { topic: "ice cream" },
// highlight-next-line
streamMode: "messages-tuple"
}
);
for await (const chunk of streamResponse) {
if (chunk.event !== "messages") {
continue;
}
console.log(chunk.data[0]["content"]); // (1)!
}
```
1. The "messages-tuple" stream mode returns an iterator of tuples `(message_chunk, metadata)` where `message_chunk` is the token streamed by the LLM and `metadata` is a dictionary with information about the graph node where the LLM was called and other information.
=== "cURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/stream \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {\"topic\": \"ice cream\"},
\"stream_mode\": \"messages-tuple\"
}"
```
### Filter LLM tokens
* To filter the streamed tokens by LLM invocation, you can [associate `tags` with LLM invocations](../../how-tos/streaming.md#filter-by-llm-invocation).
* To stream tokens only from specific nodes, use `stream_mode="messages"` and [filter the outputs by the `langgraph_node` field](../../how-tos/streaming.md#filter-by-node) in the streamed metadata.
## Stream custom data
To send **custom user-defined data**:
=== "Python"
```python
async for chunk in client.runs.stream(
thread_id,
assistant_id,
input={"query": "example"},
# highlight-next-line
stream_mode="custom"
):
print(chunk.data)
```
=== "JavaScript"
```js
const streamResponse = client.runs.stream(
threadID,
assistantID,
{
input: { query: "example" },
// highlight-next-line
streamMode: "custom"
}
);
for await (const chunk of streamResponse) {
console.log(chunk.data);
}
```
=== "cURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/stream \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {\"query\": \"example\"},
\"stream_mode\": \"custom\"
}"
```
## Stream events
To stream all events, including the state of the graph:
=== "Python"
```python
async for chunk in client.runs.stream(
thread_id,
assistant_id,
input={"topic": "ice cream"},
# highlight-next-line
stream_mode="events"
):
print(chunk.data)
```
=== "JavaScript"
```js
const streamResponse = client.runs.stream(
threadID,
assistantID,
{
input: { topic: "ice cream" },
// highlight-next-line
streamMode: "events"
}
);
for await (const chunk of streamResponse) {
console.log(chunk.data);
}
```
=== "cURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/stream \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {\"topic\": \"ice cream\"},
\"stream_mode\": \"events\"
}"
```
## Stateless runs
If you don't want to **persist the outputs** of a streaming run in the [checkpointer](../../concepts/persistence.md) DB, you can create a stateless run without creating a thread:
=== "Python"
```python
from langgraph_sdk import get_client
client = get_client(url=<DEPLOYMENT_URL>, api_key=<API_KEY>)
async for chunk in client.runs.stream(
# highlight-next-line
None, # (1)!
assistant_id,
input=inputs,
stream_mode="updates"
):
print(chunk.data)
```
1. We are passing `None` instead of a `thread_id` UUID.
=== "JavaScript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL>, apiKey: <API_KEY> });
// create a streaming run
// highlight-next-line
const streamResponse = client.runs.stream(
// highlight-next-line
null, // (1)!
assistantID,
{
input,
streamMode: "updates"
}
);
for await (const chunk of streamResponse) {
console.log(chunk.data);
}
```
1. We are passing `None` instead of a `thread_id` UUID.
=== "cURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/runs/stream \
--header 'Content-Type: application/json' \
--header 'x-api-key: <API_KEY>'
--data "{
\"assistant_id\": \"agent\",
\"input\": <inputs>,
\"stream_mode\": \"updates\"
}"
```
## Join and stream
LangGraph Platform allows you to join an active [background run](../how-tos/background_run.md) and stream outputs from it. To do so, you can use [LangGraph SDK's](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/) `client.runs.join_stream` method:
=== "Python"
```python
from langgraph_sdk import get_client
client = get_client(url=<DEPLOYMENT_URL>, api_key=<API_KEY>)
# highlight-next-line
async for chunk in client.runs.join_stream(
thread_id,
# highlight-next-line
run_id, # (1)!
):
print(chunk)
```
1. This is the `run_id` of an existing run you want to join.
=== "JavaScript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL>, apiKey: <API_KEY> });
// highlight-next-line
const streamResponse = client.runs.joinStream(
threadID,
// highlight-next-line
runId // (1)!
);
for await (const chunk of streamResponse) {
console.log(chunk);
}
```
1. This is the `run_id` of an existing run you want to join.
=== "cURL"
```bash
curl --request GET \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/<RUN_ID>/stream \
--header 'Content-Type: application/json' \
--header 'x-api-key: <API_KEY>'
```
!!! warning "Outputs not buffered"
When you use `.join_stream`, output is not buffered, so any output produced before joining will not be received.
## API Reference
For API usage and implementation, refer to the [API reference](../reference/api/api_ref.html#tag/thread-runs/POST/threads/{thread_id}/runs/stream).
@@ -0,0 +1,19 @@
# Manage assistants
!!! info "Prerequisites"
- [Assistants Overview](../../../concepts/assistants.md)
LangGraph Studio lets you view, edit, and update your assistants, and allows you to run your graph using these assistant configurations.
## Graph mode
To view your assistants, click the "Manage Assistants" button in the bottom left corner.
This opens a modal for you to view all the assistants for the selected graph. Specify the assistant and its version you would like to mark as "Active", and this assistant will be used when submitting runs.
By default, the "Default configuration" option will be active. This option reflects the default configuration defined in your graph. Edits made to this configuration will be used to update the run-time configuration, but will not update or create a new assistant unless you click "Create new assistant".
## Chat mode
Chat mode enables you to switch through the different assistants in your graph via the dropdown selector at the top of the page. To create, edit, or delete assistants, use Graph mode.
@@ -0,0 +1,112 @@
!!! info "Prerequisites"
- [LangGraph Studio Overview](../../../concepts/langgraph_studio.md)
LangGraph Studio supports connecting to two types of graphs:
- Graphs deployed on [LangGraph Platform](../../../cloud/quick_start.md)
- Graphs running locally via the [LangGraph Server](../../../tutorials/langgraph-platform/local-server.md).
LangGraph Studio is accessed from the LangSmith UI, within the LangGraph Platform Deployments tab.
## Deployed application
For applications that are [deployed](../../quick_start.md) on LangGraph Platform, you can access Studio as part of that deployment. To do so, navigate to the deployment in LangGraph Platform within the LangSmith UI and click the "LangGraph Studio" button.
This will load the Studio UI connected to your live deployment, allowing you to create, read, and update the [threads](../../../concepts/persistence.md#threads), [assistants](../../../concepts/assistants.md), and [memory](../../../concepts//memory.md) in that deployment.
## Local development server
To test your locally running application using LangGraph Studio, ensure your application is set up following [this guide](https://langchain-ai.github.io/langgraph/cloud/deployment/setup/).
!!! info "LangSmith Tracing"
For local development, if you do not wish to have data traced to LangSmith, set `LANGSMITH_TRACING=false` in your application's `.env` file. With tracing disabled, no data will leave your local server.
Next, install the [LangGraph CLI](../../../concepts/langgraph_cli.md):
```
pip install -U "langgraph-cli[inmem]"
```
and run:
```
langgraph dev
```
!!! warning "Browser Compatibility"
Safari blocks `localhost` connections to Studio. To work around this, run the above command with `--tunnel` to access Studio via a secure tunnel.
This will start the LangGraph Server locally, running in-memory. The server will run in watch mode, listening for and automatically restarting on code changes. Read this [reference](https://langchain-ai.github.io/langgraph/cloud/reference/cli/#dev) to learn about all the options for starting the API server.
If successful, you will see the following logs:
> Ready!
>
> - API: [http://localhost:2024](http://localhost:2024/)
>
> - Docs: http://localhost:2024/docs
>
> - LangGraph Studio Web UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024
Once running, you will automatically be directed to LangGraph Studio.
For an already running server, access Studio by either:
1. Directly navigate to the following URL: `https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024`.
2. Within LangSmith, navigate to the LangGraph Platform Deployments tab, click the "LangGraph Studio" button, enter `http://127.0.0.1:2024` and click "Connect".
If running your server at a different host or port, simply update the `baseUrl` to match.
### (Optional) Attach a debugger
For step-by-step debugging with breakpoints and variable inspection:
```bash
# Install debugpy package
pip install debugpy
# Start server with debugging enabled
langgraph dev --debug-port 5678
```
Then attach your preferred debugger:
=== "VS Code"
Add this configuration to `launch.json`:
```json
{
"name": "Attach to LangGraph",
"type": "debugpy",
"request": "attach",
"connect": {
"host": "0.0.0.0",
"port": 5678
}
}
```
=== "PyCharm"
1. Go to Run → Edit Configurations
2. Click + and select "Python Debug Server"
3. Set IDE host name: `localhost`
4. Set port: `5678` (or the port number you chose in the previous step)
5. Click "OK" and start debugging
## Troubleshooting
For issues getting started, please see this [troubleshooting guide](../../../troubleshooting/studio.md).
## Next steps
See the following guides for more information on how to use Studio:
- [Run application](../invoke_studio.md)
- [Manage assistants](./manage_assistants.md)
- [Manage threads](../threads_studio.md)
- [Iterate on prompts](../iterate_graph_studio.md)
- [Debug LangSmith traces](../clone_traces_studio.md)
- [Add node to dataset](../datasets_studio.md)
@@ -0,0 +1,57 @@
# Run experiments over a dataset
LangGraph Studio supports evaluations by allowing you to run your assistant over a pre-defined LangSmith dataset. This enables you to understand how your application performs over a variety of inputs, compare the results to reference outputs, and score the results using [evaluators](../../../agents/evals.md).
This guide shows you how to run an experiment end-to-end from Studio.
---
## Prerequisites
Before running an experiment, ensure you have the following:
1. **A LangSmith dataset**: Your dataset should contain the inputs you want to test and optionally, reference outputs for comparison.
- The schema for the inputs must match the required input schema for the assistant. For more information on schemas, see [here](../../../concepts/low_level.md#schema).
- For more on creating datasets, see [How to Manage Datasets](https://docs.smith.langchain.com/evaluation/how_to_guides/manage_datasets_in_application#set-up-your-dataset).
2. **(Optional) Evaluators**: You can attach evaluators (e.g., LLM-as-a-Judge, heuristics, or custom functions) to your dataset in LangSmith. These will run automatically after the graph has processed all inputs.
- To learn more, read about [Evaluation Concepts](https://docs.smith.langchain.com/evaluation/concepts#evaluators).
3. **A running application**: The experiment can be run against:
- An application deployed on [LangGraph Platform](../../quick_start.md).
- A locally running application started via the [langgraph-cli](../../../tutorials/langgraph-platform/local-server.md).
---
## Step-by-step guide
### 1. Launch the experiment
Click the **Run experiment** button in the top right corner of the Studio page.
### 2. Select your dataset
In the modal that appears, select the dataset (or a specific dataset split) to use for the experiment and click **Start**.
### 3. Monitor the progress
All of the inputs in the dataset will now be run against the active assistant. Monitor the experiment's progress via the badge in the top right corner.
You can continue to work in Studio while the experiment runs in the background. Click the arrow icon button at any time to navigate to LangSmith and view the detailed experiment results.
---
## Troubleshooting
### "Run experiment" button is disabled
If the "Run experiment" button is disabled, check the following:
- **Deployed application**: If your application is deployed on LangGraph Platform, you may need to create a new revision to enable this feature.
- **Local development server**: If you are running your application locally, make sure you have upgraded to the latest version of the `langgraph-cli` (`pip install -U langgraph-cli`). Additionally, ensure you have tracing enabled by setting the `LANGSMITH_API_KEY` in your project's `.env` file.
### Evaluator results are missing
When you run an experiment, any attached evaluators are scheduled for execution in a queue. If you don't see results immediately, it likely means they are still pending.
+37
View File
@@ -0,0 +1,37 @@
# Manage threads
Studio allows you to view [threads](../../concepts/persistence.md#threads) from the server and edit their state.
## View threads
### Graph mode
1. In the top of the right-hand pane, select the dropdown menu to view existing threads.
1. Select the desired thread, and the thread history will populate in the right-hand side of the page.
1. To create a new thread, click `+ New Thread` and [submit a run](../how-tos/invoke_studio.md#graph-mode).
To view more granular information in the thread, drag the slider at the top of the page to the right. To view less information, drag the slider to the left. Additionally, collapse or expand individual turns, nodes, and keys of the state.
Switch between `Pretty` and `JSON` mode for different rendering formats.
### Chat mode
1. View all threads in the right-hand pane of the page.
2. Select the desired thread and the thread history will populate in the center panel.
3. To create a new thread, click the plus button and [submit a run](../how-tos/invoke_studio.md#chat-mode).
## Edit thread history
### Graph mode
To edit the state of the thread, select "edit node state" next to the desired node. Edit the node's output as desired and click "fork" to confirm. This will create a new forked run from the checkpoint of the selected node.
If you instead want to re-run the thread from a given checkpoint without editing the state, click the "Re-run from here". This will again create a new forked run from the selected checkpoint. This is useful for re-running with changes that are not specific to the state, such as the selected assistant.
### Chat mode
To edit a human message in the thread, click the edit button below the human message. Edit the message as desired and submit. This will create a new fork of the conversation history. To re-generate an AI message, click the retry icon below the AI message.
## Learn more
For more information about time travel, [see here](../../concepts/time-travel.md).
+661
View File
@@ -0,0 +1,661 @@
# How to integrate LangGraph into your React application
!!! info "Prerequisites"
- [LangGraph Platform](../../concepts/langgraph_platform.md)
- [LangGraph Server](../../concepts/langgraph_server.md)
The `useStream()` React hook provides a seamless way to integrate LangGraph into your React applications. It handles all the complexities of streaming, state management, and branching logic, letting you focus on building great chat experiences.
Key features:
- Messages streaming: Handle a stream of message chunks to form a complete message
- Automatic state management for messages, interrupts, loading states, and errors
- Conversation branching: Create alternate conversation paths from any point in the chat history
- UI-agnostic design: bring your own components and styling
Let's explore how to use `useStream()` in your React application.
The `useStream()` provides a solid foundation for creating bespoke chat experiences. For pre-built chat components and interfaces, we also recommend checking out [CopilotKit](https://docs.copilotkit.ai/coagents/quickstart/langgraph) and [assistant-ui](https://www.assistant-ui.com/docs/runtimes/langgraph).
## Installation
```bash
npm install @langchain/langgraph-sdk @langchain/core
```
## Example
```tsx
"use client";
import { useStream } from "@langchain/langgraph-sdk/react";
import type { Message } from "@langchain/langgraph-sdk";
export default function App() {
const thread = useStream<{ messages: Message[] }>({
apiUrl: "http://localhost:2024",
assistantId: "agent",
messagesKey: "messages",
});
return (
<div>
<div>
{thread.messages.map((message) => (
<div key={message.id}>{message.content as string}</div>
))}
</div>
<form
onSubmit={(e) => {
e.preventDefault();
const form = e.target as HTMLFormElement;
const message = new FormData(form).get("message") as string;
form.reset();
thread.submit({ messages: [{ type: "human", content: message }] });
}}
>
<input type="text" name="message" />
{thread.isLoading ? (
<button key="stop" type="button" onClick={() => thread.stop()}>
Stop
</button>
) : (
<button keytype="submit">Send</button>
)}
</form>
</div>
);
}
```
## Customizing Your UI
The `useStream()` hook takes care of all the complex state management behind the scenes, providing you with simple interfaces to build your UI. Here's what you get out of the box:
- Thread state management
- Loading and error states
- Interrupts
- Message handling and updates
- Branching support
Here are some examples on how to use these features effectively:
### Loading States
The `isLoading` property tells you when a stream is active, enabling you to:
- Show a loading indicator
- Disable input fields during processing
- Display a cancel button
```tsx
export default function App() {
const { isLoading, stop } = useStream<{ messages: Message[] }>({
apiUrl: "http://localhost:2024",
assistantId: "agent",
messagesKey: "messages",
});
return (
<form>
{isLoading && (
<button key="stop" type="button" onClick={() => stop()}>
Stop
</button>
)}
</form>
);
}
```
### Resume a stream after page refresh
The `useStream()` hook can automatically resume an ongoing run upon mounting by setting `reconnectOnMount: true`. This is useful for continuing a stream after a page refresh, ensuring no messages and events generated during the downtime are lost.
```tsx
const thread = useStream<{ messages: Message[] }>({
apiUrl: "http://localhost:2024",
assistantId: "agent",
reconnectOnMount: true,
});
```
By default the ID of the created run is stored in `window.sessionStorage`, which can be swapped by passing a custom storage in `reconnectOnMount` instead. The storage is used to persist the in-flight run ID for a thread (under `lg:stream:${threadId}` key).
```tsx
const thread = useStream<{ messages: Message[] }>({
apiUrl: "http://localhost:2024",
assistantId: "agent",
reconnectOnMount: () => window.localStorage,
});
```
You can also manually manage the resuming process by using the run callbacks to persist the run metadata and the `joinStream` function to resume the stream. Make sure to pass `streamResumable: true` when creating the run; otherwise some events might be lost.
```tsx
import type { Message } from "@langchain/langgraph-sdk";
import { useStream } from "@langchain/langgraph-sdk/react";
import { useCallback, useState, useEffect, useRef } from "react";
export default function App() {
const [threadId, onThreadId] = useSearchParam("threadId");
const thread = useStream<{ messages: Message[] }>({
apiUrl: "http://localhost:2024",
assistantId: "agent",
threadId,
onThreadId,
onCreated: (run) => {
window.sessionStorage.setItem(`resume:${run.thread_id}`, run.run_id);
},
onFinish: (_, run) => {
window.sessionStorage.removeItem(`resume:${run?.thread_id}`);
},
});
// Ensure that we only join the stream once per thread.
const joinedThreadId = useRef<string | null>(null);
useEffect(() => {
if (!threadId) return;
const resume = window.sessionStorage.getItem(`resume:${threadId}`);
if (resume && joinedThreadId.current !== threadId) {
thread.joinStream(resume);
joinedThreadId.current = threadId;
}
}, [threadId]);
return (
<form
onSubmit={(e) => {
e.preventDefault();
const form = e.target as HTMLFormElement;
const message = new FormData(form).get("message") as string;
thread.submit(
{ messages: [{ type: "human", content: message }] },
{ streamResumable: true }
);
}}
>
<div>
{thread.messages.map((message) => (
<div key={message.id}>{message.content as string}</div>
))}
</div>
<input type="text" name="message" />
<button type="submit">Send</button>
</form>
);
}
// Utility method to retrieve and persist data in URL as search param
function useSearchParam(key: string) {
const [value, setValue] = useState<string | null>(() => {
const params = new URLSearchParams(window.location.search);
return params.get(key) ?? null;
});
const update = useCallback(
(value: string | null) => {
setValue(value);
const url = new URL(window.location.href);
if (value == null) {
url.searchParams.delete(key);
} else {
url.searchParams.set(key, value);
}
window.history.pushState({}, "", url.toString());
},
[key]
);
return [value, update] as const;
}
```
### Thread Management
Keep track of conversations with built-in thread management. You can access the current thread ID and get notified when new threads are created:
```tsx
const [threadId, setThreadId] = useState<string | null>(null);
const thread = useStream<{ messages: Message[] }>({
apiUrl: "http://localhost:2024",
assistantId: "agent",
threadId: threadId,
onThreadId: setThreadId,
});
```
We recommend storing the `threadId` in your URL's query parameters to let users resume conversations after page refreshes.
### Messages Handling
The `useStream()` hook will keep track of the message chunks received from the server and concatenate them together to form a complete message. The completed message chunks can be retrieved via the `messages` property.
By default, the `messagesKey` is set to `messages`, where it will append the new messages chunks to `values["messages"]`. If you store messages in a different key, you can change the value of `messagesKey`.
```tsx
import type { Message } from "@langchain/langgraph-sdk";
import { useStream } from "@langchain/langgraph-sdk/react";
export default function HomePage() {
const thread = useStream<{ messages: Message[] }>({
apiUrl: "http://localhost:2024",
assistantId: "agent",
messagesKey: "messages",
});
return (
<div>
{thread.messages.map((message) => (
<div key={message.id}>{message.content as string}</div>
))}
</div>
);
}
```
Under the hood, the `useStream()` hook will use the `streamMode: "messages-tuple"` to receive a stream of messages (i.e. individual LLM tokens) from any LangChain chat model invocations inside your graph nodes. Learn more about messages streaming in the [streaming](../how-tos/streaming.md#messages) guide.
### Interrupts
The `useStream()` hook exposes the `interrupt` property, which will be filled with the last interrupt from the thread. You can use interrupts to:
- Render a confirmation UI before executing a node
- Wait for human input, allowing agent to ask the user with clarifying questions
Learn more about interrupts in the [How to handle interrupts](../../how-tos/human_in_the_loop/wait-user-input.ipynb) guide.
```tsx
const thread = useStream<{ messages: Message[] }, { InterruptType: string }>({
apiUrl: "http://localhost:2024",
assistantId: "agent",
messagesKey: "messages",
});
if (thread.interrupt) {
return (
<div>
Interrupted! {thread.interrupt.value}
<button
type="button"
onClick={() => {
// `resume` can be any value that the agent accepts
thread.submit(undefined, { command: { resume: true } });
}}
>
Resume
</button>
</div>
);
}
```
### Branching
For each message, you can use `getMessagesMetadata()` to get the first checkpoint from which the message has been first seen. You can then create a new run from the checkpoint preceding the first seen checkpoint to create a new branch in a thread.
A branch can be created in following ways:
1. Edit a previous user message.
2. Request a regeneration of a previous assistant message.
```tsx
"use client";
import type { Message } from "@langchain/langgraph-sdk";
import { useStream } from "@langchain/langgraph-sdk/react";
import { useState } from "react";
function BranchSwitcher({
branch,
branchOptions,
onSelect,
}: {
branch: string | undefined;
branchOptions: string[] | undefined;
onSelect: (branch: string) => void;
}) {
if (!branchOptions || !branch) return null;
const index = branchOptions.indexOf(branch);
return (
<div className="flex items-center gap-2">
<button
type="button"
onClick={() => {
const prevBranch = branchOptions[index - 1];
if (!prevBranch) return;
onSelect(prevBranch);
}}
>
Prev
</button>
<span>
{index + 1} / {branchOptions.length}
</span>
<button
type="button"
onClick={() => {
const nextBranch = branchOptions[index + 1];
if (!nextBranch) return;
onSelect(nextBranch);
}}
>
Next
</button>
</div>
);
}
function EditMessage({
message,
onEdit,
}: {
message: Message;
onEdit: (message: Message) => void;
}) {
const [editing, setEditing] = useState(false);
if (!editing) {
return (
<button type="button" onClick={() => setEditing(true)}>
Edit
</button>
);
}
return (
<form
onSubmit={(e) => {
e.preventDefault();
const form = e.target as HTMLFormElement;
const content = new FormData(form).get("content") as string;
form.reset();
onEdit({ type: "human", content });
setEditing(false);
}}
>
<input name="content" defaultValue={message.content as string} />
<button type="submit">Save</button>
</form>
);
}
export default function App() {
const thread = useStream({
apiUrl: "http://localhost:2024",
assistantId: "agent",
messagesKey: "messages",
});
return (
<div>
<div>
{thread.messages.map((message) => {
const meta = thread.getMessagesMetadata(message);
const parentCheckpoint = meta?.firstSeenState?.parent_checkpoint;
return (
<div key={message.id}>
<div>{message.content as string}</div>
{message.type === "human" && (
<EditMessage
message={message}
onEdit={(message) =>
thread.submit(
{ messages: [message] },
{ checkpoint: parentCheckpoint }
)
}
/>
)}
{message.type === "ai" && (
<button
type="button"
onClick={() =>
thread.submit(undefined, { checkpoint: parentCheckpoint })
}
>
<span>Regenerate</span>
</button>
)}
<BranchSwitcher
branch={meta?.branch}
branchOptions={meta?.branchOptions}
onSelect={(branch) => thread.setBranch(branch)}
/>
</div>
);
})}
</div>
<form
onSubmit={(e) => {
e.preventDefault();
const form = e.target as HTMLFormElement;
const message = new FormData(form).get("message") as string;
form.reset();
thread.submit({ messages: [message] });
}}
>
<input type="text" name="message" />
{thread.isLoading ? (
<button key="stop" type="button" onClick={() => thread.stop()}>
Stop
</button>
) : (
<button key="submit" type="submit">
Send
</button>
)}
</form>
</div>
);
}
```
For advanced use cases you can use the `experimental_branchTree` property to get the tree representation of the thread, which can be used to render branching controls for non-message based graphs.
### Optimistic Updates
You can optimistically update the client state before performing a network request to the agent, allowing you to provide immediate feedback to the user, such as showing the user message immediately before the agent has seen the request.
```tsx
const stream = useStream({
apiUrl: "http://localhost:2024",
assistantId: "agent",
messagesKey: "messages",
});
const handleSubmit = (text: string) => {
const newMessage = { type: "human" as const, content: text };
stream.submit(
{ messages: [newMessage] },
{
optimisticValues(prev) {
const prevMessages = prev.messages ?? [];
const newMessages = [...prevMessages, newMessage];
return { ...prev, messages: newMessages };
},
}
);
};
```
### Cached Thread Display
Use the `initialValues` option to display cached thread data immediately while the history is being loaded from the server. This improves user experience by showing cached data instantly when navigating to existing threads.
```tsx
import { useStream } from "@langchain/langgraph-sdk/react";
const CachedThreadExample = ({ threadId, cachedThreadData }) => {
const stream = useStream({
apiUrl: "http://localhost:2024",
assistantId: "agent",
threadId,
// Show cached data immediately while history loads
initialValues: cachedThreadData?.values,
messagesKey: "messages",
});
return (
<div>
{stream.messages.map((message) => (
<div key={message.id}>{message.content as string}</div>
))}
</div>
);
};
```
### Optimistic Thread Creation
Use the `threadId` option in `submit` function to enable optimistic UI patterns where you need to know the thread ID before the thread is actually created.
```tsx
import { useState } from "react";
import { useStream } from "@langchain/langgraph-sdk/react";
const OptimisticThreadExample = () => {
const [threadId, setThreadId] = useState<string | null>(null);
const [optimisticThreadId] = useState(() => crypto.randomUUID());
const stream = useStream({
apiUrl: "http://localhost:2024",
assistantId: "agent",
threadId,
onThreadId: setThreadId, // (3) Updated after thread has been created.
messagesKey: "messages",
});
const handleSubmit = (text: string) => {
// (1) Perform a soft navigation to /threads/${optimisticThreadId}
// without waiting for thread creation.
window.history.pushState({}, "", `/threads/${optimisticThreadId}`);
// (2) Submit message to create thread with the predetermined ID.
stream.submit(
{ messages: [{ type: "human", content: text }] },
{ threadId: optimisticThreadId }
);
};
return (
<div>
<p>Thread ID: {threadId ?? optimisticThreadId}</p>
{/* Rest of component */}
</div>
);
};
```
### TypeScript
The `useStream()` hook is friendly for apps written in TypeScript and you can specify types for the state to get better type safety and IDE support.
```tsx
// Define your types
type State = {
messages: Message[];
context?: Record<string, unknown>;
};
// Use them with the hook
const thread = useStream<State>({
apiUrl: "http://localhost:2024",
assistantId: "agent",
messagesKey: "messages",
});
```
You can also optionally specify types for different scenarios, such as:
- `ConfigurableType`: Type for the `config.configurable` property (default: `Record<string, unknown>`)
- `InterruptType`: Type for the interrupt value - i.e. contents of `interrupt(...)` function (default: `unknown`)
- `CustomEventType`: Type for the custom events (default: `unknown`)
- `UpdateType`: Type for the submit function (default: `Partial<State>`)
```tsx
const thread = useStream<
State,
{
UpdateType: {
messages: Message[] | Message;
context?: Record<string, unknown>;
};
InterruptType: string;
CustomEventType: {
type: "progress" | "debug";
payload: unknown;
};
ConfigurableType: {
model: string;
};
}
>({
apiUrl: "http://localhost:2024",
assistantId: "agent",
messagesKey: "messages",
});
```
If you're using LangGraph.js, you can also reuse your graph's annotation types. However, make sure to only import the types of the annotation schema in order to avoid importing the entire LangGraph.js runtime (i.e. via `import type { ... }` directive).
```tsx
import {
Annotation,
MessagesAnnotation,
type StateType,
type UpdateType,
} from "@langchain/langgraph/web";
const AgentState = Annotation.Root({
...MessagesAnnotation.spec,
context: Annotation<string>(),
});
const thread = useStream<
StateType<typeof AgentState.spec>,
{ UpdateType: UpdateType<typeof AgentState.spec> }
>({
apiUrl: "http://localhost:2024",
assistantId: "agent",
messagesKey: "messages",
});
```
## Event Handling
The `useStream()` hook provides several callback options to help you respond to different events:
- `onError`: Called when an error occurs.
- `onFinish`: Called when the stream is finished.
- `onUpdateEvent`: Called when an update event is received.
- `onCustomEvent`: Called when a custom event is received. See the [streaming](../../how-tos/streaming.md#stream-custom-data) guide to learn how to stream custom events.
- `onMetadataEvent`: Called when a metadata event is received, which contains the Run ID and Thread ID.
## Learn More
- [JS/TS SDK Reference](../reference/sdk/js_ts_sdk_ref.md)

Some files were not shown because too many files have changed in this diff Show More