- Delete `security.md` as it will be inherited from
`langchain-ai/.github`
- Move `CONTRIBUTING.md` to `.github` (will still appear on homepage),
cleaning up top level
- Copy contents of `AGENTS.md` to `CLAUDE.md` since CC still doesn't
take `AGENTS.md`
**Description**: The Agent Server API now supports counting assistants
by name.
This is similar to adding the `name` parameter to the Assistants search
API: https://github.com/langchain-ai/langgraph/pull/6483
**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>
**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
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)
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
## 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).
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
`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
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
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>
## 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'}`
```
## 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
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.
`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.
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.
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.
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
**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
- **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
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
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
This syncs the checkpoint interface specification with the base class
(`BaseCheckpointSaver`) in
`langgraph/libs/checkpoint/langgraph/checkpoint/base /__init__.py`.
**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
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
```
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`
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
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"]}}
```
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.
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
* 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 :/
**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
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>
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.
### 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>
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>
### 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
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
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>
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]
```
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`.
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.
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.
### 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>
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>
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.)
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>
### 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.
**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>
### 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>
**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>
## 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
### 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
## 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
### 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`)
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>
**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
* 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.
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>
### 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")`
:-------------------------:|:-------------------------:

|

* 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
:-------------------------:|:-------------------------:

|

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>
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).
### 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>
### 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
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.
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>
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></tr></table>
</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 />
[](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>
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
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'`
**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
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
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.
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>
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>
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>
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>
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>
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>
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>
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.
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.
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.
### 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
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>
- 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
`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.
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.
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!
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>
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>
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
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>
**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>
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"
/>
**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>
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>
## 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
- **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>
Fixes#5735
Implement context coercion functionality for LangGraph runtime to
improve API usability.
Key changes:
- Added `_coerce_context` function in `pregel/main.py`
- Supports coercion for:
- Pydantic BaseModel
- Dataclasses
- TypedDict
- Comprehensive test coverage added in `tests/test_runtime.py`
- Handles edge cases like None context and missing fields
The implementation allows users to pass dictionaries as context, which
will be automatically converted to the expected schema type, making the
API more flexible and user-friendly.
---------
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Sydney Runkle <sydneymarierunkle@gmail.com>
Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
**docs: The notebook redirects to a page that does not exist**
- **Description:** The current documentation redirects to a file that
does not exist. I have removed the doc to avoid confusion.
- **Issue:** Fixes#5637
**Description:**
Removed 4 broken notebooks in `examples/human_in_the_loop/` that
referenced missing files (list below). These notebooks displayed
redirect messages but the new paths are either invalid or don’t contain
content.
Filenames:
1. examples/human_in_the_loop/dynamic_breakpoints.ipynb
2. examples/human_in_the_loop/edit-graph-state.ipynb
3. examples/human_in_the_loop/review-tool-calls.ipynb
4. examples/human_in_the_loop/time-travel.ipynb
**Issue:**
Closes#5642
**Dependencies:**
None
Co-authored-by: gawhaarya <gawhaneaarya@gmail.com>
## Description
Previously, when a tool returned `Command` to update the graph's state,
the `_validate_tool_command` method in `ToolNode` would raise a
`ValueError` if the `messages_update` list contained only a
`RemoveMessage(id=REMOVE_ALL_MESSAGES)` object. This was because the
validation logic expected a matching `ToolMessage` for the tool call and
did not account for this specific state-clearing scenario.
This commit modifies the validation logic to check if the
`messages_update` list contains a single
`RemoveMessage(id=REMOVE_ALL_MESSAGES)` element. If this condition is
met, the `ToolMessage` validation is bypassed, allowing a tool to clear
the entire message history without causing a validation error.
A new test case, `test_tool_node_command_remove_all_messages`, has been
added to `tests/test_tool_node.py` to verify this change and prevent
future regressions.
## Example
Here is a self-contained example that illustrates the problem and the
fix. Without this change, the code block for `Example 2` would raise a
`ValueError`.
```python
from typing import Annotated, List
from langchain_core.messages import (
AIMessage,
AnyMessage,
HumanMessage,
RemoveMessage,
ToolMessage,
)
from langchain_core.tools import InjectedToolCallId, tool
from langchain_openai import ChatOpenAI
from langgraph.graph import END, StateGraph, add_messages
from langgraph.graph.message import REMOVE_ALL_MESSAGES
from langgraph.prebuilt import InjectedState, ToolNode
from langgraph.types import Command
from pydantic import BaseModel, Field
# Agent state tracks current and all messages
class AgentState(BaseModel):
messages: Annotated[List[AnyMessage], add_messages] = Field(
default_factory=list, description="Current conversation messages."
)
all_messages: Annotated[List[AnyMessage], add_messages] = Field(
default_factory=list, description="All messages, including removed ones."
)
# Tool to clear history if long enough, otherwise returns a warning
@tool
def clear_history_tool(
state: Annotated[AgentState, InjectedState],
tool_call_id: Annotated[str, InjectedToolCallId],
):
"""Clears message history if it's long enough."""
if len(state.messages) < 3:
return Command(
update={
"messages": [
ToolMessage(
"History is not long enough to be cleared. Please try again.",
tool_call_id=tool_call_id,
)
]
}
)
else:
return Command(
update={
"messages": [RemoveMessage(id=REMOVE_ALL_MESSAGES)],
"all_messages": state.messages
+ [
ToolMessage(
"History has been successfully cleared.",
tool_call_id=tool_call_id,
)
],
}
)
# Bind the tool to the model
model = ChatOpenAI(model="gpt-4o-mini").bind_tools([clear_history_tool])
def model_node(state: AgentState):
return {"messages": [model.invoke(state.messages)]}
# Build the agent graph
graph_builder = StateGraph(AgentState)
graph_builder.add_node("model", model_node)
graph_builder.add_node("tools", ToolNode([clear_history_tool]))
graph_builder.set_entry_point("model")
graph_builder.add_edge("model", "tools")
graph_builder.add_edge("tools", END)
graph = graph_builder.compile()
def print_messages(header, messages):
print(f"\n{header}")
for message in messages:
message.pretty_print()
### Example 1: Not enough history to clear
state_1 = AgentState(
messages=[HumanMessage(content="Please clear my message history.")]
)
output_1 = graph.invoke(state_1)
print_messages("First call: State 'messages'", output_1["messages"])
print_messages("First call: State 'all_messages'", output_1["all_messages"])
### Example 2: History is cleared
state_2 = AgentState(
messages=[
HumanMessage(content="Will this PR get merged?"),
AIMessage(content="Maybe, if it's good enough."),
HumanMessage(content="Please clear my message history."),
]
)
# Without the changes in this PR, the following line will raise a ValueError
output_2 = graph.invoke(state_2)
print_messages("Second call: State 'messages'", output_2["messages"])
print_messages("Second call: State 'all_messages'", output_2["all_messages"])
```
### Outputs
*Without the changes in this PR:*
```
First call: State 'messages'
================================ Human Message =================================
Please clear my message history.
================================== Ai Message ==================================
Tool Calls:
clear_history_tool (ba421ac3-1e1a-4208-a8f6-c5500ee0abcc)
Call ID: ba421ac3-1e1a-4208-a8f6-c5500ee0abcc
Args:
================================= Tool Message =================================
Name: clear_history_tool
History is not long enough to be cleared. Please try again.
First call: State 'all_messages'
Traceback (most recent call last):
File "main.py", line 114, in <module>
output_2 = graph.invoke(state_2)
^^^^^^^^^^^^^^^^^^^^^
File ".venv/lib/python3.11/site-packages/langgraph/pregel/__init__.py", line 2844, in invoke
for chunk in self.stream(
File ".venv/lib/python3.11/site-packages/langgraph/pregel/__init__.py", line 2534, in stream
for _ in runner.tick(
File ".venv/lib/python3.11/site-packages/langgraph/prebuilt/tool_node.py", line 241, in _func
outputs = [
^
File ".venv/lib/python3.11/concurrent/futures/_base.py", line 619, in result_iterator
yield _result_or_cancel(fs.pop())
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File ".venv/lib/python3.11/concurrent/futures/_base.py", line 317, in _result_or_cancel
return fut.result(timeout)
^^^^^^^^^^^^^^^^^^^
File ".venv/lib/python3.11/concurrent/futures/_base.py", line 449, in result
return self.__get_result()
^^^^^^^^^^^^^^^^^^^
File ".venv/lib/python3.11/concurrent/futures/_base.py", line 401, in __get_result
raise self._exception
File ".venv/lib/python3.11/concurrent/futures/thread.py", line 58, in run
result = self.fn(*self.args, **self.kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File ".venv/lib/python3.11/site-packages/langchain_core/runnables/config.py", line 555, in _wrapped_fn
return contexts.pop().run(fn, *args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File ".venv/lib/python3.11/site-packages/langgraph/prebuilt/tool_node.py", line 353, in _run_one
return self._validate_tool_command(response, call, input_type)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File ".venv/lib/python3.11/site-packages/langgraph/prebuilt/tool_node.py", line 616, in _validate_tool_command
raise ValueError(
ValueError: Expected to have a matching ToolMessage in Command.update for tool 'clear_history_tool', got: [RemoveMessage(content='', additional_kwargs={}, response_metadata={}, id='__remove_all__')]. Every tool call (LLM requesting to call a tool) in the message history MUST have a corresponding ToolMessage. You can fix it by modifying the tool to return `Command(update={"messages": [ToolMessage("Success", tool_call_id=tool_call_id), ...]}, ...)`.
```
*With the changes in this PR:*
```
First call: State 'messages'
================================ Human Message =================================
Please clear my message history.
================================== Ai Message ==================================
Tool Calls:
clear_history_tool (ba421ac3-1e1a-4208-a8f6-c5500ee0abcc)
Call ID: ba421ac3-1e1a-4208-a8f6-c5500ee0abcc
Args:
================================= Tool Message =================================
Name: clear_history_tool
History is not long enough to be cleared. Please try again.
First call: State 'all_messages'
Second call: State 'messages'
Second call: State 'all_messages'
================================ Human Message =================================
Will this PR get merged?
================================== Ai Message ==================================
Maybe, if it's good enough.
================================ Human Message =================================
Please clear my message history.
================================== Ai Message ==================================
Tool Calls:
clear_history_tool (499b1be3-6df1-493f-85e5-8d7e429dead8)
Call ID: 499b1be3-6df1-493f-85e5-8d7e429dead8
Args:
================================= Tool Message =================================
Name: clear_history_tool
History has been successfully cleared.
```
## Twitter handle
[@samuelpullely](https://x.com/samuelpullely)
---------
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
Introduces a syntax for cross-reference links that work across language
and change behavior depending on which scope they appear in.
```markdown
@[interrupt]
:::python
@[StateGraph]
:::
:::js
@[create_react_agent]
:::
```
Can be compiled to
```markdown
# a link that changes based on global context or compile target
<div> ... </div> -> `interrupt` in global context
:::python
[StateGraph](link to python cross reference)
:::
:::js
[create_react_agent](link to js cross reference)
:::
```
TODO:
- [x] fix broken unit test
- [x] no f strings in logger (it's a sin)
- [x] remove cross-refs.txt (we'll instead start updating the cross link
map)
Automated changelog update created by the LangGraph Server Changelog
Bot.
Feel free to merge anytime.
---------
Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com>
This PR allows a developer to change the model configuration at run time based on context. This includes that list of tools available to the model to call.
```python
def create_react_agent(
model: Union[
str,
LanguageModelLike,
Callable[[SateLike, Runtime...], BaseChatModel], # <--- New
],
tools: Union[
Sequence[Union[BaseTool, Callable, dict[str, Any]]], ToolNode]
],
*,
....
llm = init_chat_model(...)
def prepare_model(state, runtime):
selected_tool_names = func(state, context)
return llm.bind(tools=selected_tool_names)
create_react_agent(
prepare_model,
tools=all_known_tools
)
```
## Semantics
1. `tools` = are the known tools, used to configure ToolNode and will
configure:
1. model provided as string
2. model provided as BaseChatModel (if it has no tools bound to it)
2. If a user provides a dynamic model (callable), the user is
responsible for binding tools
Alternative considered:
1. Passing `Callable[[SateLike, Config...], list[BaseTool]]` to tools
2. Passing `Callable[[SateLike, Config...], list[str]]` to a tool
selector
Both have the issue that there's non obvious interplay between tool
selection and dynamic models. (i.e., if we want to introduce dynamic
models at in the future, the API will become tricky to explain)
---------
Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
Adding support for the `context` arg to `invoke/stream` to the sdk. This
is paired with an update to the API as well that adds `context` support
to the `assistants` and `runs` endpoints.
Bumping version to v0.2.0 on the `v1` branch given this and the
interrupt schema changes.
- Replaces checkpoint_during: bool
- checkpoint_during is deprecated but still respected
- We implement three durability modes (from least to most durable):
- "exit" - save checkpoint only when the graph exits (equivalent to
checkpoint_during=False)
- "async" - save checkpoint asynchronously while the next step executes
(the default, equivalent to old checkpoint_during=True)
- "sync" - save checkpoint synchronously before the next step starts
(new mode, slower but most durable)
Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
* Cleaning up the underlying tool injection logic which is happening in
multiple locations.
* State was being injected into the ToolCall via Send in two places in
create react agent and the logic doesn't belong there, the actual
injection should be happening inside the ToolNode where there's
awareness of what run time parameters the tool accepts.
Change is required to unblock:
https://github.com/langchain-ai/langgraph/pull/5537
Fixes#5554
This PR removes unused utility classes and functions from the prebuilt
tests directory to clean up dead code.
Changes include:
- Removed unused classes from `libs/prebuilt/tests/any_str.py`:
- Deleted FloatBetween, AnyDict, AnyVersion, and UnsortedSequence
- Kept only AnyStr class
- Removed unused functions from `libs/prebuilt/tests/messages.py`:
- Deleted _AnyIdDocument and _AnyIdAIMessageChunk
- Kept _AnyIdHumanMessage and _AnyIdToolMessage
- Removed unused classes from `libs/prebuilt/tests/memory_assert.py`:
- Deleted NoopSerializer, MemorySaverAssertCheckpointMetadata, and
MemorySaverNoPending
- Kept MemorySaverAssertImmutable
Verification:
- Manually checked for no remaining references to removed code
- Maintained existing import structures
- Preserved functionality of the prebuilt test suite
The changes reduce code complexity and remove unnecessary utility
classes that were not being used in the test suite.
---------
Co-authored-by: open-swe-dev[bot] <open-swe-dev@users.noreply.github.com>
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
- Channels containing primitive values don't need to be stored in separate rows in blobs table, as the overhead of a separate row will usually be higher than the size of the value
- This applies for instance to all internal channels used to manage edges, so it has a big impact just from that. It can also apply to user-managed channels depending on their values
- The same channel may switch storage between versions without any issue
* docs: Add codespell for markdown files
* update
* remove path
* fix
* update linting guidelines
* chore[deps]: upgrade dependencies with `uv lock --upgrade` (#5471)
Co-authored-by: sydney-runkle <54324534+sydney-runkle@users.noreply.github.com>
* fix(checkpoint): correct logging call to use logger (#5458)
fix[checkpoint]: correct logging call to use logger
* release(langgraph): v0.5.3 (#5498)
bump
* extend to cover python files used for reference docs
* fix(docs): Update the graph image link (#5500)
Update the graph image link
Point to the correct image reference for Map-Reduce and the Send API example
* fix(docs): Update graph-api.md File to reflect correct image (#5499)
Update graph-api.md File to reflect correct image
Referencing to the correct image file
* docs(prebuilt): improve documentation in ToolNode module (#5497)
Update documentation in ToolNode module
* Update changelog via LangGraph Server Changelog Bot
* feat(sdk-py): Show is_studio_user (#5505)
* Update changelog via LangGraph Server Changelog Bot
* fix(docs): Node caching explanation code required a small fix,. (#5473)
fix(docs): Node caching explanation code required a small fix, to avoid confusion to readers. The code had `time.sleep(2)` but the note mentioned one second only.
Co-authored-by: ygicp <yagnesh@infocusp.com>
* fix(langgraph): add `stacklevel=2` to the warnings to point to the caller’s codes (#5457)
chore: add stacklevel=2 to the warnings to point to the caller’s codes
* chore(docs): Improve example in use mcp (#5480)
* Make example more explicit
* Update docs/docs/agents/mcp.md
* fix(docs): update examples link (#5515)
Co-authored-by: ahmed murtaza <ahmed.gmurtaza@gmail.com>
* docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5514)
Update changelog via LangGraph Server Changelog Bot
* fix readmes
* fix
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: sydney-runkle <54324534+sydney-runkle@users.noreply.github.com>
Co-authored-by: Michael Li <michaelli65535@gmail.com>
Co-authored-by: Sakshi Gupta <64280320+sakshi1989@users.noreply.github.com>
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
Co-authored-by: Sam Crowder <samecrowder@gmail.com>
Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com>
Co-authored-by: Yagnesh M. Bhadiyadra <35532869+yagneshmb@users.noreply.github.com>
Co-authored-by: ygicp <yagnesh@infocusp.com>
Co-authored-by: Ahmed Murtaza <ahmed.gmurtaza@hotmail.com>
Co-authored-by: ahmed murtaza <ahmed.gmurtaza@gmail.com>
fix(docs): Node caching explanation code required a small fix, to avoid confusion to readers. The code had `time.sleep(2)` but the note mentioned one second only.
Co-authored-by: ygicp <yagnesh@infocusp.com>
This commit fixes#5503
Gist of it is:
- `asyncio.exception.InvalidStateError` were being raised when the
future was cancelled
- this exception bubbled up and killed the background task
- `AsyncBatchedBaseStore` stopped doing queries because the background
task wasn't running anymore
This commit adds some "if future is not done" checks to guard against
this.
* docs: static vs dynamic interrupts
* fixes based on feedback
* fix image
* Add section about debugging in Studio
* Reorg content based on feedback
* fix
* fix links
* fix wording
* fix wording
Consolidating the hooks to avoid duplication of logic
We need this change for consolidating js and python content: we need include-markdown to run as a mkdocs plugin before our pipeline (rather than as markdown extension which runs after our hooks plugin).
* feat: add copy page button functionality and fix llms-text output
- Add copy page button with CSS and JS implementation
- Implement copy page hooks for MkDocs integration
- Fix HTML filtering and DOM text reinterpreted as HTML issues
- Update llms-text target to generate docs/llm.txt instead of docs/llms-full.txt
- Add necessary styling and package.json dependencies
* fix missing button in preview
* remove the over-processing
* disable API reference
* Add RESUMABLE_STREAM_TTL_SECONDS to env vars list.
* Update default value for BG_JOB_SHUTDOWN_GRACE_PERIOD_SECS.
* Update LANGGRAPH_POSTGRES_POOL_MAX_SIZE description.
Update quick_start.md Rest API Guide
The curl command in the quick start needs some minor changes to work out of the box. I hope by adding these changes then new users can get started more quickly
* Create user_agent_auth.md
Adding documentation for agent authentication on behalf of a user
* Update user_agent_auth.md
* Rename user_agent_auth.md to user-agent-auth.md
* break content out to separate guides
* add links/overview
* edits
* fix sentence
* Fix broken links
* Fix: Change 'get_user_config' fn name to 'my_node'
* Fix: Add reference to custom auth in MCP docs example
---------
Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
* public interfaces for channels
* public interfaces for func
* public interfaces for graph
* pi for managed
* first pass public interface for top level modules
* first pass at private for utils -> _internal
* private interface for pregel
* scratchpad/stream protocol move
* docs update
* backwards compat for runnable
* deprecation warning for send and interrupt
* deprecation for pregel import
Add onStop callback to useStream hook enabling developers to customize
UI behavior when streams are stopped. This is especially useful for
UI messages with loading states that need to show "stopped" status
instead of remaining in infinite loading state.
The callback provides the same mutate function as onCustomEvent for
immediate local state updates, while users can optionally update
server thread state using the threads client.
Example usage:
```typescript
const stream = useStream({
assistantId: "my-assistant",
onStop: async ({ mutate }) => {
// Immediate UI update - stop loading components
mutate((prev) => ({
...prev,
ui: prev.ui?.map(component =>
component.props?.isLoading
? {
...component,
props: {
...component.props,
isLoading: false,
isStopped: true
}
}
: component
)
}));
// Optional server thread state update
if (stream.threadId) {
await stream.client.threads.updateState(stream.threadId, {
values: {
ui: prev.ui // persist stopped state to server
}
});
}
}
});
```
This is especially useful for cases where gen UI components have loading states,
where we don't want the loading state to persist on cancellation.
- Convert BytesLineDecoder and SSEDecoder from classes extending TransformStream to factory functions
- Fixes tree shaking failures that prevented build completion
- Maintains identical API functionality, just removes 'new' keyword usage
- All tests continue to pass
Resolves tree shaking side effect detection issues with TransformStream extension
- Document initialValues for cached thread display
- Document newThreadId for optimistic thread creation
- Add comprehensive test coverage for both features
Add initialValues parameter to UseStreamOptions to enable immediate display
of cached thread data while official history is being fetched from the server.
This addresses the common use case where applications cache thread data
locally (IndexedDB, localStorage, etc.) and want to show it instantly when
users navigate to existing threads, providing better UX with faster loading.
Key changes:
- Add initialValues?: Partial<StateType> | null to UseStreamOptions interface
- Update values precedence: streamValues > initialValues > historyValues
- Ensure optimisticValues properly override initialValues during submission
- Maintain full backward compatibility with existing API
Example usage:
```typescript
const stream = useStream({
threadId,
assistantId: 'my-assistant',
initialValues: cachedThreadData?.values // Show cached data immediately
});
```
The values flow now follows this priority:
1. Initial load: shows initialValues while history loads
2. During submit: optimisticValues take precedence
3. After server response: official history replaces all
Add optional newThreadId parameter to useStream hook that allows specifying
a thread ID for new thread creation while keeping threadId null. This enables
optimistic UI patterns where developers need to know the thread ID beforehand
for routing/navigation without causing 404 errors from attempting to fetch
non-existent thread history.
Usage:
- Set threadId: null and newThreadId: "predetermined-id"
- Submit message to create thread with specified ID
- Use onThreadId callback to update threadId after creation
This solves the UX problem of having to await thread creation before
enabling optimistic navigation to e.g. /[threadId] routes.
Hi there! Thank you for even being interested in contributing to LangGraph.
As an open-source project in a rapidly developing field, we are extremely open to contributions, whether they involve new features, improved infrastructure, better documentation, or bug fixes.
To learn how to contribute to LangGraph, please follow the [contribution guide here](https://docs.langchain.com/oss/python/contributing).
description:Report a bug in LangGraph. To report a security issue, please instead use the security option below. For questions, please use the GitHub Discussions.
labels:[pending,bug]
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]
body:
- type:markdown
attributes:
value:>
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 [GitHub Discussions](https://github.com/langchain-ai/langgraph/discussions).
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
description:Before submitting this issue, please confirm that you have completed all the steps below by checking each option. These steps help ensure your issue is well-defined, relevant, and actionable.
options:
- label:This is a bug, not a usage question. For questions, please use GitHub Discussions.
- label:This is a bug, not a usage question. For questions, please use the LangChain Forum (https://forum.langchain.com/).
required:true
- label:I added a clear and detailed title that summarizes the issue.
required:true
@@ -38,7 +38,7 @@ body:
attributes:
label:Example Code
description:|
Please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with your use case.
Please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with your use case. Replace this code with your own!
placeholder:|
from langgraph.graph import StateGraph
@@ -78,7 +78,7 @@ body:
attributes:
label:System Info
description:|
python -m langchain_core.sys_info
Run on your machine: `python -m langchain_core.sys_info`
description:You are a LangChain maintainer, or was asked directly by a maintainer to create an issue here. If not, check the other options.
description:You are a LangGraph maintainer, or was asked directly by a maintainer to create an issue here. If not, check the other options.
body:
- type:markdown
attributes:
value:|
Thanks for your interest in LangChain! 🚀
If you are not a LangChain maintainer or were not asked directly by a maintainer to create an issue, then please start the conversation in a [Question in GitHub Discussions](https://github.com/langchain-ai/langchain/discussions/categories/q-a) instead.
You are a LangChain maintainer if you maintain any of the packages inside of the LangChain repository
or are a regular contributor to LangChain with previous merged merged pull requests.
Thanks for your interest in LangGraph! 🚀
If you are not a LangGraph maintainer or were not asked directly by a maintainer to create an issue, then please start the conversation on the [LangChain Forum](https://forum.langchain.com/) instead.
You are a LangGraph maintainer if you maintain any of the packages inside of the LangGraph repository
or are a regular contributor to LangGraph with previous merged merged pull requests.
- type:checkboxes
id:privileged
attributes:
label:Privileged issue
description:Confirm that you are allowed to create an issue here.
options:
- label:I am a LangChain maintainer, or was asked directly by a LangChain maintainer to create an issue here.
- label:I am a LangGraph maintainer, or was asked directly by a LangGraph maintainer to create an issue here.
required:true
- type:textarea
id:content
attributes:
label:Issue Content
description:Add the content of the issue here.
- type:markdown
attributes:
value:|
Community members should **NOT** work on Privileged issues unless these issues have been explicitly marked with a "help-wanted" tag.
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}
- 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.
Thank you for being interested in contributing to LangGraph!
## General guidelines
Here are some things to keep in mind for all types of contributions:
- Follow the ["fork and pull request"](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project) workflow.
- Fill out the checked-in pull request template when opening pull requests. Note related issues and tag relevant maintainers.
- Ensure your PR passes formatting, linting, and testing checks before requesting a review.
- If you would like comments or feedback, please open an issue or discussion and tag a maintainer.
- Backwards compatibility is key. Your changes must not be breaking, except in case of critical bug and security fixes.
- Look for duplicate PRs or issues that have already been opened before opening a new one.
- Keep scope as isolated as possible. As a general rule, your changes should not affect more than one package at a time.
### Bugfixes
For bug fixes, please open up an issue before proposing a fix to ensure the proposal properly addresses the underlying problem. In general, bug fixes should all have an accompanying unit test that fails before the fix.
### New features
For new features, please start a new [discussion](https://github.com/langchain-ai/langgraph/discussions), where the maintainers will help with scoping out the necessary changes.
## Contribute Documentation
Documentation is a vital part of LangGraph. We welcome both new documentation for new features and
community improvements to our current documentation. Please read the resources below before getting started:
As LangGraph continues to grow, the surface area of documentation required to cover it continues to grow too.
This page provides guidelines for anyone writing documentation for LangGraph, as well as some of our philosophies around organization and structure.
## Philosophy
LangGraph's documentation follows the [Diataxis framework](https://diataxis.fr).
Under this framework, all documentation falls under one of four categories: [Tutorials](#tutorials),
[How-to guides](#how-to-guides),
[References](#references), and [Explanations (aka conceptual guides)](#conceptual-guide).
### Tutorials
Tutorials are lessons that take the reader through a practical activity. Their purpose is to help the user
gain understanding of concepts and how they interact by showing one way to achieve some goal in a hands-on way.
They should **avoid** giving
multiple permutations of ways to achieve that goal in-depth. Choice is burdensome. Instead, they should guide a new user through a recommended path to accomplishing a concrete goal. While the end result of a tutorial does not necessarily need to
be completely production-ready, it should be useful and practically satisfy the goal that you clearly stated in the tutorial's introduction.
To quote the Diataxis website:
> A tutorial serves the user’s *acquisition* of skills and knowledge - their study. Its purpose is not to help the user get something done, but to help them learn.
In LangGraph, these are often higher level guides that show off end-to-end use cases.
Some examples include:
- [Build a Customer Support Bot](https://langchain-ai.github.io/langgraph/tutorials/customer-support/customer-support/)
- [Build a SQL Agent](https://langchain-ai.github.io/langgraph/tutorials/sql-agent/)
Here are some high-level tips on writing a good tutorial:
- Focus on guiding the user to get something done, but keep in mind the end-goal is more to impart principles than to create a perfect production system.
- Be specific, not abstract and follow one path.
- No need to go deeply into alternative approaches, but it’s ok to reference them, ideally with a link to an appropriate how-to guide.
- Get "a point on the board" as soon as possible - something the user can run that outputs something.
- You can iterate and expand afterwards.
- Try to frequently checkpoint at given steps where the user can run code and see progress.
- Focus on results, not technical explanation.
- Crosslink heavily to appropriate conceptual/reference pages
- The first time you mention a LangGraph concept, use its full name (e.g. "human-in-the-loop"), and link to its conceptual/other documentation page.
- It's also helpful to add a prerequisite callout that links to any pages with necessary background information.
- End with a recap/next steps section summarizing what the tutorial covered and future reading, such as related how-to guides.
- Use phrases like "Next we can run X & Y. We will expect Z.". Then afterwards, use language like "Notice Z" that recalls our expectations and directs the reader's attention to the topic we are trying to teach.
- Do not shy away from repetition.
### How-to guides
A how-to guide, as the name implies, demonstrates how to do something discrete and specific.
It should assume that the user is already familiar with underlying concepts, and is trying to solve an immediate problem, but
should still give some background or list the scenarios where the information contained within can be relevant.
They can and should discuss alternatives if one approach may be better than another in certain cases.
To quote the Diataxis website:
> A how-to guide serves the work of the already-competent user, whom you can assume to know what they want to do, and to be able to follow your instructions correctly.
Some examples include:
- [How to add persistence to your graph](https://langchain-ai.github.io/langgraph/how-tos/persistence/)
- [How to view and update past graph state](https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/time-travel/)
Here are some high-level tips on writing a good how-to guide:
- Clearly explain what you are guiding the user through at the start
- Assume higher intent than a tutorial and show what the user needs to do to get that task done
- Assume familiarity of concepts, but explain why suggested actions are helpful
- Crosslink heavily to conceptual/reference pages
- Discuss alternatives and responses to real-world tradeoffs that may arise when solving a problem
- Use lots of example code, ideally within complete code blocks that the reader can copy and run.
- End with a recap/next steps section summarizing what the tutorial covered and future reading, such as other related how-to guides
### Conceptual guides
LangGraph's conceptual guides fall under the **Explanation** quadrant of Diataxis. They should cover LangChain terms and concepts
in a more abstract way than how-to guides or tutorials, and should be geared towards curious users interested in
gaining a deeper understanding of the framework. Try to avoid excessively large code examples. The goal here is to
impart perspective to the user rather than to finish a practical project. These guides should cover **why** things work the way they do.
To quote the Diataxis website:
> The perspective of explanation is higher and wider than that of the other types. It does not take the user’s eye-level view, as in a how-to guide, or a close-up view of the machinery, like reference material. Its scope in each case is a topic - “an area of knowledge”, that somehow has to be bounded in a reasonable, meaningful way.
Some examples include:
- [What does it mean to be agentic?](https://langchain-ai.github.io/langgraph/concepts/high_level/)
Here are some high-level tips on writing a good conceptual guide:
- Explain design decisions. Why does concept X exist and why was it designed this way?
- Use analogies and reference other concepts and alternatives
- Avoid blending in too much reference content
- You can and should reference content covered in other guides, but make sure to link to them
### References
References contain detailed, low-level information that describes exactly what functionality exists and how to use it.
In LangGraph, this is mainly our API reference pages, which are populated from docstrings within code.
References pages are generally not read end-to-end, but are consulted as necessary when a user needs to know
how to use something specific.
To quote the Diataxis website:
> The only purpose of a reference guide is to describe, as succinctly as possible, and in an orderly way. Whereas the content of tutorials and how-to guides are led by needs of the user, reference material is led by the product it describes.
Many of the reference pages in LangChain are automatically generated from code,
but here are some high-level tips on writing a good docstring:
- Be concise
- Discuss special cases and deviations from a user's expectations
- Go into detail on required inputs and outputs
- Light details on when one might use the feature are fine, but in-depth details belong in other sections.
Each category serves a distinct purpose and requires a specific approach to writing and structuring the content.
## General guidelines
Here are some other guidelines you should think about when writing and organizing documentation.
We generally do not merge new tutorials from outside contributors without an actual need.
We welcome updates as well as new integration docs, how-tos, and references.
### Avoid duplication
Multiple pages that cover the same material in depth are difficult to maintain and cause confusion. There should
be only one (very rarely two), canonical pages for a given concept or feature. Instead, you should link to other guides.
### Link to other sections
Because sections of the docs do not exist in a vacuum, it is important to link to other sections as often as possible
to allow a developer to learn more about an unfamiliar topic inline.
This includes linking to the API references as well as conceptual sections!
### Be concise
In general, take a less-is-more approach. If a section with a good explanation of a concept already exists, you should link to it rather than
re-explain it, unless the concept you are documenting presents some new wrinkle.
Be concise, including in code samples.
### General style
- Use active voice and present tense whenever possible
- Use examples and code snippets to illustrate concepts and usage
- Use appropriate header levels (`#`, `##`, `###`, etc.) to organize the content hierarchically
- Use fewer cells with more code to make copy/paste easier
- Use bullet points and numbered lists to break down information into easily digestible chunks
- Use tables (especially for **Reference** sections) and diagrams often to present information visually
- Include the table of contents for longer documentation pages to help readers navigate the content, but hide it for shorter pages
## Setup
LangChain documentation consists of two components:
1. Main Documentation: Hosted at [https://langchain-ai.github.io](https://langchain-ai.github.io/langgraph/),
this comprehensive resource serves as the primary user-facing documentation.
It covers a wide array of topics, including tutorials, use cases, integrations,
and more, offering extensive guidance on building with LangGraph.
The content for this documentation lives in the `/docs` directory of the monorepo.
2. In-code Documentation: This is documentation of the codebase itself, which is also
used to generate the externally facing [API Reference](https://langchain-ai.github.io/langgraph/reference/graphs/).
The content for the API reference is autogenerated by scanning the docstrings in the codebase. For this reason we ask that developers document their code well.
We appreciate all contributions to the documentation, whether it be fixing a typo,
adding a new tutorial or example and whether it be in the main documentation or the API Reference.
### 📜 Main Documentation
The content for the main documentation is located in the `/docs` directory of the monorepo.
The documentation is written using a combination of ipython notebooks (`.ipynb` files)
and markdown (`.md` files). The notebooks are converted to markdown
and then built using [MkDocs](https://www.mkdocs.org/).
Feel free to make contributions to the main documentation! 🥰
After modifying the documentation:
1. Run the linting and formatting commands (see below) to ensure that the documentation is well-formatted and free of errors.
2. Optionally build the documentation locally to verify that the changes look good.
3. Make a pull request with the changes.
### ⚒️ Linting and Building Documentation Locally
After writing up the documentation, you may want to lint and build the documentation
locally to ensure that it looks good and is free of errors.
If you're unable to build it locally that's okay as well, as you will be able to
see a preview of the documentation on the pull request page.
From the **monorepo root**, run the following command to install the dependencies:
<!-- TODO -->
```bash
poetry install --with docs --no-root
```
#### Building
The code that builds the documentation is located in the `/docs` directory of the monorepo.
Before building the documentation, it is always a good idea to clean the build directory:
```bash
make clean-docs
```
You can build and preview the documentation as outlined below:
```bash
make serve-docs
```
#### Linting
The documentation is linted from the **monorepo root**. To lint it, run the following from there:
```bash
make spellcheck
```
### ️In-code Documentation
The in-code documentation is autogenerated from docstrings.
For the API reference to be useful, the codebase must be well-documented. This means that all functions, classes, and methods should have a docstring that explains what they do, what the arguments are, and what the return value is. This is a good practice in general, but it is especially important for LangChain because the API reference is the primary resource for developers to understand how to use the codebase.
We generally follow the [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings) for docstrings.
Here is an example of a well-documented function:
```python
defmy_function(arg1:int,arg2:str)->float:
"""This is a short description of the function. (It should be a single sentence.)
This is a longer description of the function. It should explain what
the function does, what the arguments are, and what the return value is.
It should wrap at 88 characters.
Examples:
This is a section for examples of how to use the function.
.. code-block:: python
my_function(1, "hello")
Args:
arg1: This is a description of arg1. We do not need to specify the type since
it is already specified in the function signature.
@@ -63,17 +63,18 @@ 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/tutorials/overview/): Guided examples on getting started with LangGraph.
- [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.
- [LangChain Academy](https://academy.langchain.com/courses/intro-to-langgraph): Learn the basics of LangGraph in our free, structured course.
- [Templates](https://langchain-ai.github.io/langgraph/concepts/template_applications/): Pre-built reference apps for common agentic workflows (e.g. ReAct agent, memory, retrieval etc.) that can be cloned and adapted.
- [Case studies](https://www.langchain.com/built-with-langgraph): Hear how industry leaders use LangGraph to ship AI applications at scale.
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.
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
// "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
// "noUncheckedSideEffectImports": true, /* Check side effect imports. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/*Emit*/
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
// "outDir": "./", /* Specify an output folder for all emitted files. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
/*InteropConstraints*/
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
// "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */
// "erasableSyntaxOnly": true, /* Do not allow runtime constructs that are not part of ECMAScript. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
| [LinkedIn](https://www.linkedin.com/) | Social Media | Code generation; Search & discovery | [Blog post, 2025](https://www.linkedin.com/blog/engineering/ai/practical-text-to-sql-for-data-analytics); [Blog post, 2024](https://www.linkedin.com/blog/engineering/generative-ai/behind-the-platform-the-journey-to-create-the-linkedin-genai-application-tech-stack) |
| [LinkedIn](https://www.linkedin.com/) | Social Media | Code generation; Search & discovery | [Interrupt talk, 2025](https://youtu.be/NmblVxyBhi8?feature=shared); [Blog post, 2025](https://www.linkedin.com/blog/engineering/ai/practical-text-to-sql-for-data-analytics); [Blog post, 2024](https://www.linkedin.com/blog/engineering/generative-ai/behind-the-platform-the-journey-to-create-the-linkedin-genai-application-tech-stack) |
| [WebToon](https://www.webtoons.com/en/) | Media & Entertainment | Data extraction | [Case study, 2025](https://blog.langchain.com/customers-webtoon/) |
`@langchain/core``@langchain/anthropic` are installed so the agent can call the [model](https://js.langchain.com/docs/integrations/chat/).
:::
## 2. Create an agent
To create an agent, use [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent]:
:::python
To create an agent, use @[`create_react_agent`][create_react_agent]:
```python
fromlanggraph.prebuiltimportcreate_react_agent
@@ -52,13 +69,56 @@ agent.invoke(
)
```
1. Define a tool for the agent to use. Tools can be defined as vanilla Python functions. For more advanced tool usage and customization, check the [tools](./tools.md) page.
1. Define a tool for the agent to use. Tools can be defined as vanilla Python functions. For more advanced tool usage and customization, check the [tools](../how-tos/tool-calling.md) page.
2. Provide a language model for the agent to use. To learn more about configuring language models for the agents, check the [models](./models.md) page.
3. Provide a list of tools for the model to use.
4. Provide a system prompt (instructions) to the language model used by the agent.
:::
:::js
To create an agent, use [`createReactAgent`](https://langchain-ai.github.io/langgraphjs/reference/functions/langgraph_prebuilt.createReactAgent.html):
stateModifier:"You are a helpful assistant",// (4)!
});
// Run the agent
awaitagent.invoke({
messages:[{role:"user",content:"what is the weather in sf"}],
});
```
1. Define a tool for the agent to use. Tools can be defined using the `tool` function. For more advanced tool usage and customization, check the [tools](./tools.md) page.
2. Provide a language model for the agent to use. To learn more about configuring language models for the agents, check the [models](./models.md) page.
3. Provide a list of tools for the model to use.
4. Provide a system prompt (instructions) to the language model used by the agent.
:::
## 3. Configure an LLM
:::python
To configure an LLM with specific parameters, such as temperature, use [init_chat_model](https://python.langchain.com/api_reference/langchain/chat_models/langchain.chat_models.base.init_chat_model.html):
```python
@@ -79,19 +139,45 @@ agent = create_react_agent(
)
```
:::
:::js
To configure an LLM with specific parameters, such as temperature, use a model instance:
{ messages: [{ role: "user", content: "what is the weather in sf" }] },
// highlight-next-line
{ configurable: { user_name: "John Smith" } }
);
```
1. Dynamic prompts allow including non-message [context](./context.md) when constructing an input to the LLM, such as:
- Information passed at runtime, like a `user_id` or API credentials (using `config`).
- Internal agent state updated during a multi-step reasoning process (using `state`).
Dynamic prompts can be defined as functions that take `state` and `config` and return a list of messages to send to the LLM.
:::
For more information, see [Context](./context.md).
## 5. Add memory
To allow multi-turn conversations with an agent, you need to enable [persistence](../concepts/persistence.md) by providing a `checkpointer` when creating an agent. At runtime, you need to provide a config containing `thread_id` — a unique identifier for the conversation (session):
To allow multi-turn conversations with an agent, you need to enable [persistence](../concepts/persistence.md) by providing a checkpointer when creating an agent. At runtime, you need to provide a config containing `thread_id` — a unique identifier for the conversation (session):
:::python
```python
from langgraph.prebuilt import create_react_agent
@@ -182,8 +329,50 @@ ny_response = agent.invoke(
1. `checkpointer` allows the agent to store its state at every step in the tool calling loop. This enables [short-term memory](../how-tos/memory/add-memory.md#add-short-term-memory) and [human-in-the-loop](../concepts/human_in_the_loop.md) capabilities.
2. Pass configuration with `thread_id` to be able to resume the same conversation on future agent invocations.
:::
:::js
```typescript
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { MemorySaver } from "@langchain/langgraph";
{ messages: [{ role: "user", content: "what is the weather in sf" }] },
// highlight-next-line
config // (2)!
);
const nyResponse = await agent.invoke(
{ messages: [{ role: "user", content: "what about new york?" }] },
// highlight-next-line
config
);
```
1. `checkpointSaver` allows the agent to store its state at every step in the tool calling loop. This enables [short-term memory](../how-tos/memory/add-memory.md#add-short-term-memory) and [human-in-the-loop](../concepts/human_in_the_loop.md) capabilities.
2. Pass configuration with `thread_id` to be able to resume the same conversation on future agent invocations.
:::
:::python
When you enable the checkpointer, it stores agent state at every step in the provided checkpointer database (or in memory, if using `InMemorySaver`).
:::
:::js
When you enable the checkpointer, it stores agent state at every step in the provided checkpointer database (or in memory, if using `MemorySaver`).
:::
Note that in the above example, when the agent is invoked the second time with the same `thread_id`, the original message history from the first conversation is automatically included, together with the new user input.
@@ -191,6 +380,7 @@ For more information, see [Memory](../how-tos/memory/add-memory.md).
## 6. Configure structured output
:::python
To produce structured responses conforming to a schema, use the `response_format` parameter. The schema can be defined with a `Pydantic` model or `TypedDict`. The result will be accessible via the `structured_response` field.
```python
@@ -215,9 +405,43 @@ response = agent.invoke(
response["structured_response"]
```
1. When `response_format` is provided, a separate step is added at the end of the agent loop: agent message history is passed to an LLM with structured output to generate a structured response.
1. When `response_format` is provided, a separate step is added at the end of the agent loop: agent message history is passed to an LLM with structured output to generate a structured response.
To provide a system prompt to this LLM, use a tuple `(prompt, schema)`, e.g., `response_format=(prompt, WeatherResponse)`.
To provide a system prompt to this LLM, use a tuple `(prompt, schema)`, e.g., `response_format=(prompt, WeatherResponse)`.
:::
:::js
To produce structured responses conforming to a schema, use the `responseFormat` parameter. The schema can be defined with a `Zod` schema. The result will be accessible via the `structuredResponse` field.
```typescript
import { z } from "zod";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
const WeatherResponse = z.object({
conditions: z.string(),
});
const agent = createReactAgent({
llm: "anthropic:claude-3-5-sonnet-latest",
tools: [getWeather],
// highlight-next-line
responseFormat: WeatherResponse, // (1)!
});
const response = await agent.invoke({
messages: [{ role: "user", content: "what is the weather in sf" }],
});
// highlight-next-line
response.structuredResponse;
```
1. When `responseFormat` is provided, a separate step is added at the end of the agent loop: agent message history is passed to an LLM with structured output to generate a structured response.
To provide a system prompt to this LLM, use an object `{ prompt, schema }`, e.g., `responseFormat: { prompt, schema: WeatherResponse }`.
**Context engineering** is the practice of building dynamic systems that provide the right information and tools, in the right format, so that a language model can plausibly accomplish a task.
**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:
Context includes *any* data outside the message list that can shape behavior. This can be:
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)
2. By **lifetime**:
- **Runtime context**: Data scoped to a single run or invocation
- **Cross-conversation context**: Data that persists across multiple conversations or sessions
- Information passed at runtime, like a `user_id` or API credentials.
- Internal state updated during a multi-step reasoning process.
- Persistent memory or facts from previous interactions.
!!! tip "Runtime context vs LLM context"
LangGraph provides **three**primary ways to supply context:
Runtime context refers to local context: data and dependencies your code needs to run. It does **not**refer to:
| [**Config**](#config-static-context) | data passed at the start of a run | ❌ | per run |
| [**Short-term memory (State)**](#short-term-memory-mutable-context) | dynamic data that can change during execution | ✅ | per run or conversation |
| [**Long-term memory (Store)**](#long-term-memory-cross-conversation-context) | data that can be shared between conversations | ✅ | across conversations |
* The LLM context, which is the data passed into the LLM's prompt.
* The "context window", which is the maximum number of tokens that can be passed to the LLM.
## Provide runtime context
Runtime context can be used to optimize the LLM context. For example, you can use user metadata
in the runtime context to fetch user preferences and feed them into the context window.
### Config (static context)
LangGraph provides three ways to manage context, which combines the mutability and lifetime dimensions:
Config is for immutable data like user metadata or API keys. Use
when you have values that don't change mid-run.
:::python
Specify configuration using a key called **"configurable"** which is reserved
| [**Static runtime context**](#static-runtime-context) | User metadata, tools, db connections passed at startup | Static | Single run | `context` argument to `invoke`/`stream` |
| [**Dynamic runtime context (state)**](#dynamic-runtime-context-state) | Mutable data that evolves during a single run | Dynamic | Single run | LangGraph state object |
| [**Dynamic cross-conversation context (store)**](#dynamic-cross-conversation-context-store) | Persistent data shared across conversations | Dynamic | Cross-conversation | LangGraph store |
## Static runtime context
**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 "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']`.
1. This is the invocation of the agent or graph. The `invoke` method runs the underlying graph with the provided input.
2. This example uses messages as an input, which is common, but your application may use different input structures.
3. This is where you pass the configuration data. The `config` parameter allows you to provide additional context that the agent can use during its execution.
3. This is where you pass the runtime data. The `context` parameter allows you to provide additional dependencies that the agent can use during its execution.
=== "Agent prompt"
```python
from langchain_core.messages import AnyMessage
from langchain_core.runnables import RunnableConfig
from langgraph.runtime import get_runtime
from langgraph.prebuilt.chat_agent_executor import AgentState
See the [tool calling guide](../how-tos/tool-calling.md#configuration) for details.
### Short-term memory (mutable context)
!!! tip
State acts as [short-term memory](../concepts/memory.md) during a run. It holds dynamic data that can evolve during execution, such as values derived from tools or LLM outputs.
The `Runtime` object can be used to access static context and other utilities like the active store and stream writer.
See the [Runtime][langgraph.runtime.Runtime] documentation for details.
:::
:::js
| Context type | Description | Mutability | Lifetime |
**Dynamic runtime context** represents mutable data that can evolve during a single run and is managed through the LangGraph state object. This includes conversation history, intermediate results, and values derived from tools or LLM outputs. In LangGraph, the state object acts as [short-term memory](../concepts/memory.md) during a run.
=== "In an agent"
@@ -105,6 +156,7 @@ State acts as [short-term memory](../concepts/memory.md) during a run. It holds
State can also be accessed by the agent's **tools**, which can read or update the state as needed. See [tool calling guide](../how-tos/tool-calling.md#short-term-memory) for details.
:::python
```python
from langchain_core.messages import AnyMessage
from langchain_core.runnables import RunnableConfig
@@ -139,10 +191,51 @@ State acts as [short-term memory](../concepts/memory.md) during a run. It holds
1. Define a custom state schema that extends `AgentState` or `MessagesState`.
2. Pass the custom state schema to the agent. This allows the agent to access and modify the state during execution.
:::
:::js
```typescript
import type { BaseMessage } from "@langchain/core/messages";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { MessagesZodState } from "@langchain/langgraph";
import { z } from "zod";
// highlight-next-line
const CustomState = z.object({ // (1)!
messages: MessagesZodState.shape.messages,
userName: z.string(),
});
const prompt = (
// highlight-next-line
state: z.infer<typeof CustomState>
): BaseMessage[] => {
const userName = state.userName;
const systemMsg = `You are a helpful assistant. User's name is ${userName}`;
1. Define a custom state schema that extends `MessagesZodState` or creates a new schema.
2. Pass the custom state schema to the agent. This allows the agent to access and modify the state during execution.
:::
=== "In a workflow"
:::python
```python
from typing_extensions import TypedDict
from langchain_core.messages import AnyMessage
@@ -167,18 +260,49 @@ State acts as [short-term memory](../concepts/memory.md) during a run. It holds
builder.set_entry_point("node")
graph = builder.compile()
```
1. Define a custom state
2. Access the state in any node or tool
3. The Graph API is designed to work as easily as possible with state. The return value of a node represents a requested update to the state.
:::
:::js
```typescript
import type { BaseMessage } from "@langchain/core/messages";
import { StateGraph, MessagesZodState, START } from "@langchain/langgraph";
import { z } from "zod";
// highlight-next-line
const CustomState = z.object({ // (1)!
messages: MessagesZodState.shape.messages,
extraField: z.number(),
});
const builder = new StateGraph(CustomState)
.addNode("node", async (state) => { // (2)!
const messages = state.messages;
// ...
return { // (3)!
// highlight-next-line
extraField: state.extraField + 1,
};
})
.addEdge(START, "node");
const graph = builder.compile();
```
1. Define a custom state
2. Access the state in any node or tool
3. The Graph API is designed to work as easily as possible with state. The return value of a node represents a requested update to the state.
:::
!!! tip "Turning on memory"
Please see the [memory guide](../how-tos/memory/add-memory.md) for more details on how to enable memory. This is a powerful feature that allows you to persist the agent's state across multiple invocations. Otherwise, the state is scoped only to a single run.
### Long-term memory (cross-conversation context)
## Dynamic cross-conversation context (store)
For context that spans *across* conversations or sessions, LangGraph allows access to **long-term memory** via a `store`. This can be used to read or update persistent facts (e.g., user profiles, preferences, prior interactions).
**Dynamic cross-conversation context** represents persistent, mutable data that spans across multiple conversations or sessions and is managed through the LangGraph store. This includes user profiles, preferences, and historical interactions. The LangGraph store acts as [long-term memory](../concepts/memory.md#long-term-memory) across multiple runs. This can be used to read or update persistent facts (e.g., user profiles, preferences, prior interactions).
For more information, see the [Memory guide](../how-tos/memory/add-memory.md).
For more information, see the [Memory guide](../how-tos/memory/add-memory.md).
To evaluate your agent's performance you can use `LangSmith` [evaluations](https://docs.smith.langchain.com/evaluation). You would need to first define an evaluator function to judge the results from an agent, such as final outputs or trajectory. Depending on your evaluation technique, this may or may not involve a reference output:
To get started, you can use prebuilt evaluators from `AgentEvals` package:
:::python
```bash
pip install -U agentevals
```
:::
:::js
```bash
npm install agentevals
```
:::
## Create evaluator
A common way to evaluate agent performance is by comparing its trajectory (the order in which it calls its tools) against a reference trajectory:
:::python
```python
importjson
# highlight-next-line
@@ -80,8 +117,63 @@ result = evaluator(
)
```
1. Specify how the trajectories will be compared. `superset` will accept output trajectory as valid if it's a superset of the reference one. Other options include: [strict](https://github.com/langchain-ai/agentevals?tab=readme-ov-file#strict-match), [unordered](https://github.com/langchain-ai/agentevals?tab=readme-ov-file#unordered-match) and [subset](https://github.com/langchain-ai/agentevals?tab=readme-ov-file#subset-and-superset-match)
// Specify how the trajectories will be compared. `superset` will accept output trajectory as valid if it's a superset of the reference one. Other options include: strict, unordered and subset
trajectoryMatchMode:"superset",// (1)!
});
// Run the evaluator
constresult=evaluator({
outputs: outputs,
referenceOutputs: referenceOutputs,
});
```
:::
1. Specify how the trajectories will be compared. `superset` will accept output trajectory as valid if it's a superset of the reference one. Other options include: [strict](https://github.com/langchain-ai/agentevals?tab=readme-ov-file#strict-match), [unordered](https://github.com/langchain-ai/agentevals?tab=readme-ov-file#unordered-match) and [subset](https://github.com/langchain-ai/agentevals?tab=readme-ov-file#subset-and-superset-match)
As a next step, learn more about how to [customize trajectory match evaluator](https://github.com/langchain-ai/agentevals?tab=readme-ov-file#agent-trajectory-match).
@@ -89,6 +181,8 @@ As a next step, learn more about how to [customize trajectory match evaluator](h
You can use LLM-as-a-judge evaluator that uses an LLM to compare the trajectory against the reference outputs and output a score:
To run an evaluator, you will first need to create a [LangSmith dataset](https://docs.smith.langchain.com/evaluation/concepts#datasets). To use the prebuilt AgentEvals evaluators, you will need a dataset with the following schema:
@@ -110,6 +222,8 @@ To run an evaluator, you will first need to create a [LangSmith dataset](https:/
- **input**: `{"messages": [...]}` input messages to call the agent with.
- **output**: `{"messages": [...]}` expected message history in the agent output. For trajectory evaluation, you can choose to keep only assistant messages.
messages: [{ role: "user", content: "what is the weather in nyc?" }],
});
```
:::
## Custom MCP servers
:::python
To create your own MCP servers, you can use the `mcp` library. This library provides a simple way to define tools and run them as servers.
Install the MCP library:
@@ -118,8 +258,24 @@ Install the MCP library:
```bash
pip install mcp
```
:::
:::js
To create your own MCP servers, you can use the `@modelcontextprotocol/sdk` library. This library provides a simple way to define tools and run them as servers.
Install the MCP SDK:
```bash
npm install @modelcontextprotocol/sdk
```
:::
Use the following reference implementations to test your agent with MCP tool servers.
:::python
```python title="Example Math Server (stdio transport)"
from mcp.server.fastmcp import FastMCP
@@ -139,6 +295,115 @@ if __name__ == "__main__":
mcp.run(transport="stdio")
```
:::
:::js
```typescript title="Example Math Server (stdio transport)"
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
LangGraph provides built-in support for [LLMs (language models)](https://python.langchain.com/docs/concepts/chat_models/) via the LangChain library. This makes it easy to integrate various LLMs into your agents and workflows.
## Initialize a model
:::python
Use [`init_chat_model`](https://python.langchain.com/docs/how_to/chat_models_universal_init/) to initialize models:
import { ChatAnthropic } from "@langchain/anthropic";
const model = new ChatAnthropic({
model: "claude-3-5-sonnet-20240620",
temperature: 0,
maxTokens: 2048,
});
```
=== "Google"
```typescript
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
const model = new ChatGoogleGenerativeAI({
model: "gemini-1.5-pro",
temperature: 0,
});
```
=== "Groq"
```typescript
import { ChatGroq } from "@langchain/groq";
const model = new ChatGroq({
model: "llama-3.1-70b-versatile",
temperature: 0,
});
```
:::
:::python
### Instantiate a model directly
If a model provider is not available via `init_chat_model`, you can instantiate the provider's model class directly. The model must implement the [BaseChatModel interface](https://python.langchain.com/api_reference/core/language_models/langchain_core.language_models.chat_models.BaseChatModel.html) and support tool calling:
```python
# Anthropic is already supported by `init_chat_model`,
# but you can also instantiate it directly.
@@ -26,19 +78,20 @@ model = ChatAnthropic(
)
```
:::
!!! important "Tool calling support"
If you are building an agent or workflow that requires the model to call external tools, ensure that the underlying
language model supports [tool calling](../concepts/tools.md). Compatible models can be found in the [LangChain integrations directory](https://python.langchain.com/docs/integrations/chat/).
## Use in an agent
:::python
When using `create_react_agent` you can specify the model by its name string, which is a shorthand for initializing the model using `init_chat_model`. This allows you to use the model without needing to import or instantiate it directly.
=== "model name"
```python
from langgraph.prebuilt import create_react_agent
@@ -70,10 +123,103 @@ When using `create_react_agent` you can specify the model by its name string, wh
)
```
:::
:::js
When using `createReactAgent` you can pass the model instance directly:
```typescript
import { ChatOpenAI } from "@langchain/openai";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
const model = new ChatOpenAI({
model: "gpt-4o",
temperature: 0,
});
const agent = createReactAgent({
llm: model,
tools: tools,
});
```
:::
:::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
To disable streaming of the individual LLM tokens, set `disable_streaming=True` when initializing the model:
=== "`init_chat_model`"
@@ -101,9 +247,25 @@ To disable streaming of the individual LLM tokens, set `disable_streaming=True`
```
Refer to the [API reference](https://python.langchain.com/api_reference/core/language_models/langchain_core.language_models.chat_models.BaseChatModel.html#langchain_core.language_models.chat_models.BaseChatModel.disable_streaming) for more information on `disable_streaming`
:::
:::js
To disable streaming of the individual LLM tokens, set `streaming: false` when initializing the model:
```typescript
import { ChatOpenAI } from "@langchain/openai";
const model = new ChatOpenAI({
model: "gpt-4o",
streaming: false,
});
```
:::
### Add model fallbacks
:::python
You can add a fallback to a different model or a different LLM provider using `model.with_fallbacks([...])`:
=== "`init_chat_model`"
@@ -136,6 +298,28 @@ You can add a fallback to a different model or a different LLM provider using `m
```
See this [guide](https://python.langchain.com/docs/how_to/fallbacks/#fallback-to-better-model) for more information on model fallbacks.
:::
:::js
You can add a fallback to a different model or a different LLM provider using `model.withFallbacks([...])`:
```typescript
import { ChatOpenAI } from "@langchain/openai";
import { ChatAnthropic } from "@langchain/anthropic";
const modelWithFallbacks = new ChatOpenAI({
model: "gpt-4o",
}).withFallbacks([
new ChatAnthropic({
model: "claude-3-5-sonnet-20240620",
}),
]);
```
See this [guide](https://js.langchain.com/docs/how_to/fallbacks/#fallback-to-better-model) for more information on model fallbacks.
See the LangChain docs for more information on how to [handle rate limiting](https://python.langchain.com/docs/how_to/chat_model_rate_limiting/).
:::
## Bring your own model
If your desired LLM isn't officially supported by LangChain, consider these options:
:::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`.
Refer to the [custom streaming documentation](../how-tos/streaming.md#use-with-any-llm) for guidance. This approach suits custom workflows where prebuilt agent integration is not necessary.
@@ -22,6 +22,7 @@ Two of the most popular multi-agent architectures are:

:::python
Use [`langgraph-supervisor`](https://github.com/langchain-ai/langgraph-supervisor-py) library to create a supervisor multi-agent system:
```bash
@@ -82,10 +83,76 @@ for chunk in supervisor.stream(
print("\n")
```
:::
:::js
Use [`@langchain/langgraph-supervisor`](https://github.com/langchain-ai/langgraphjs/tree/main/libs/langgraph-supervisor) library to create a supervisor multi-agent system:
return`Successfully booked a flight from ${fromAirport} to ${toAirport}.`;
}
constflightAssistant=createReactAgent({
llm:"openai:gpt-4o",
tools:[bookFlight],
stateModifier:"You are a flight booking assistant",
// highlight-next-line
name:"flight_assistant",
});
consthotelAssistant=createReactAgent({
llm:"openai:gpt-4o",
tools:[bookHotel],
stateModifier:"You are a hotel booking assistant",
// highlight-next-line
name:"hotel_assistant",
});
// highlight-next-line
constsupervisor=createSupervisor({
agents:[flightAssistant,hotelAssistant],
llm: newChatOpenAI({model:"gpt-4o"}),
systemPrompt:
"You manage a hotel booking assistant and a "+
"flight booking assistant. Assign work to them.",
});
forawait(constchunkofsupervisor.stream({
messages:[
{
role:"user",
content:"book a flight from BOS to JFK and a stay at McKittrick Hotel",
},
],
})){
console.log(chunk);
console.log("\n");
}
```
:::
## Swarm

:::python
Use [`langgraph-swarm`](https://github.com/langchain-ai/langgraph-swarm-py) library to create a swarm multi-agent system:
```bash
@@ -143,18 +210,82 @@ for chunk in swarm.stream(
print("\n")
```
:::
:::js
Use [`@langchain/langgraph-swarm`](https://github.com/langchain-ai/langgraphjs/tree/main/libs/langgraph-swarm) library to create a swarm multi-agent system:
description:"Transfer user to the flight-booking assistant.",
});
constflightAssistant=createReactAgent({
llm:"anthropic:claude-3-5-sonnet-latest",
// highlight-next-line
tools:[bookFlight,transferToHotelAssistant],
stateModifier:"You are a flight booking assistant",
// highlight-next-line
name:"flight_assistant",
});
consthotelAssistant=createReactAgent({
llm:"anthropic:claude-3-5-sonnet-latest",
// highlight-next-line
tools:[bookHotel,transferToFlightAssistant],
stateModifier:"You are a hotel booking assistant",
// highlight-next-line
name:"hotel_assistant",
});
// highlight-next-line
constswarm=createSwarm({
agents:[flightAssistant,hotelAssistant],
defaultActiveAgent:"flight_assistant",
});
forawait(constchunkofswarm.stream({
messages:[
{
role:"user",
content:"book a flight from BOS to JFK and a stay at McKittrick Hotel",
},
],
})){
console.log(chunk);
console.log("\n");
}
```
:::
## Handoffs
A common pattern in multi-agent interactions is **handoffs**, where one agent *hands off* control to another. Handoffs allow you to specify:
A common pattern in multi-agent interactions is **handoffs**, where one agent _hands off_ control to another. Handoffs allow you to specify:
- **destination**: target agent to navigate to
- **payload**: information to pass to that agent
:::python
This is used both by `langgraph-supervisor` (supervisor hands off to individual agents) and `langgraph-swarm` (an individual agent can hand off to other agents).
To implement handoffs with `create_react_agent`, you need to:
1. Create a special tool that can transfer control to a different agent
1. Create a special tool that can transfer control to a different agent
```python
def transfer_to_bob():
@@ -173,7 +304,7 @@ To implement handoffs with `create_react_agent`, you need to:
)
```
1. Create individual agents that have access to handoff tools:
2. Create individual agents that have access to handoff tools:
```python
flight_assistant = create_react_agent(
@@ -184,7 +315,7 @@ To implement handoffs with `create_react_agent`, you need to:
)
```
1. Define a parent graph that contains individual agents as nodes:
3. Define a parent graph that contains individual agents as nodes:
```python
from langgraph.graph import StateGraph, MessagesState
@@ -196,8 +327,60 @@ To implement handoffs with `create_react_agent`, you need to:
)
```
:::
:::js
This is used both by `@langchain/langgraph-supervisor` (supervisor hands off to individual agents) and `@langchain/langgraph-swarm` (an individual agent can hand off to other agents).
To implement handoffs with `createReactAgent`, you need to:
1. Create a special tool that can transfer control to a different agent
```typescript
function transferToBob() {
/**Transfer to bob.*/
return new Command({
// name of the agent (node) to go to
// highlight-next-line
goto: "bob",
// data to send to the agent
// highlight-next-line
update: { messages: [...] },
// indicate to LangGraph that we need to navigate to
// agent node in a parent graph
// highlight-next-line
graph: Command.PARENT,
});
}
```
2. Create individual agents that have access to handoff tools:
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)
// ...
```
:::
Putting this together, here is how you can implement a simple multi-agent system with two agents — a flight booking assistant and a hotel booking assistant:
:::python
```python
from typing import Annotated
from langchain_core.tools import tool, InjectedToolCallId
@@ -298,11 +481,158 @@ for chunk in multi_agent_graph.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.
:::
:::js
```typescript
import { tool } from "@langchain/core/tools";
import { ChatAnthropic } from "@langchain/anthropic";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import {
StateGraph,
START,
MessagesZodState,
Command,
} from "@langchain/langgraph";
import { z } from "zod";
function createHandoffTool({
agentName,
description,
}: {
agentName: string;
description?: string;
}) {
const name = `transfer_to_${agentName}`;
const toolDescription = description || `Transfer to ${agentName}`;
return tool(
async (_, config) => {
const toolMessage = {
role: "tool" as const,
content: `Successfully transferred to ${agentName}`,
llm: new ChatAnthropic({ model: "anthropic:claude-3-5-sonnet-latest" }),
// highlight-next-line
tools: [bookFlight, transferToHotelAssistant],
stateModifier: "You are a flight booking assistant",
// highlight-next-line
name: "flight_assistant",
});
const hotelAssistant = createReactAgent({
llm: new ChatAnthropic({ model: "anthropic:claude-3-5-sonnet-latest" }),
// highlight-next-line
tools: [bookHotel, transferToFlightAssistant],
stateModifier: "You are a hotel booking assistant",
// highlight-next-line
name: "hotel_assistant",
});
// Define multi-agent graph
const multiAgentGraph = new StateGraph(MessagesZodState)
.addNode("flight_assistant", flightAssistant)
.addNode("hotel_assistant", hotelAssistant)
.addEdge(START, "flight_assistant")
.compile();
// Run the multi-agent graph
for await (const chunk of multiAgentGraph.stream({
messages: [
{
role: "user",
content: "book a flight from BOS to JFK and a stay at McKittrick Hotel",
},
],
})) {
console.log(chunk);
console.log("\n");
}
```
1. Access agent's state
2. The `Command` primitive allows specifying a state update and a node transition as a single operation, making it useful for implementing handoffs.
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
This handoff implementation assumes that:
- each agent receives overall message history (across all agents) in the multi-agent system as its input
- each agent outputs its internal messages history to the overall message history of the multi-agent system
Check out LangGraph [supervisor](https://github.com/langchain-ai/langgraph-supervisor-py#customizing-handoff-tools) and [swarm](https://github.com/langchain-ai/langgraph-swarm-py#customizing-handoff-tools) documentation to learn how to customize handoffs.
:::python
Check out LangGraph [supervisor](https://github.com/langchain-ai/langgraph-supervisor-py#customizing-handoff-tools) and [swarm](https://github.com/langchain-ai/langgraph-swarm-py#customizing-handoff-tools) documentation to learn how to customize handoffs.
:::
:::js
Check out LangGraph [supervisor](https://github.com/langchain-ai/langgraphjs/tree/main/libs/langgraph-supervisor#customizing-handoff-tools) and [swarm](https://github.com/langchain-ai/langgraphjs/tree/main/libs/langgraph-swarm#customizing-handoff-tools) documentation to learn how to customize handoffs.
@@ -14,7 +14,7 @@ LangGraph provides both low-level primitives and high-level prebuilt components
## What is an agent?
An *agent* consists of three components: a **large language model (LLM)**, a set of **tools** it can use, and a **prompt** that provides instructions.
An _agent_ consists of three components: a **large language model (LLM)**, a set of **tools** it can use, and a **prompt** that provides instructions.
The LLM operates in a loop. In each iteration, it selects a tool to invoke, provides input, receives the result (an observation), and uses that observation to inform the next action. The loop continues until a stopping condition is met — typically when the agent has gathered enough information to respond to the user.
@@ -27,12 +27,12 @@ The LLM operates in a loop. In each iteration, it selects a tool to invoke, prov
LangGraph includes several capabilities essential for building robust, production-ready agentic systems:
- [**Memory integration**](../how-tos/memory/add-memory.md): Native support for *short-term* (session-based) and *long-term* (persistent across sessions) memory, enabling stateful behaviors in chatbots and assistants.
- [**Human-in-the-loop control**](../concepts/human_in_the_loop.md): Execution can pause *indefinitely* to await human feedback—unlike websocket-based solutions limited to real-time interaction. This enables asynchronous approval, correction, or intervention at any point in the workflow.
- [**Memory integration**](../how-tos/memory/add-memory.md): Native support for _short-term_ (session-based) and _long-term_ (persistent across sessions) memory, enabling stateful behaviors in chatbots and assistants.
- [**Human-in-the-loop control**](../concepts/human_in_the_loop.md): Execution can pause _indefinitely_ to await human feedback—unlike websocket-based solutions limited to real-time interaction. This enables asynchronous approval, correction, or intervention at any point in the workflow.
- [**Streaming support**](../how-tos/streaming.md): Real-time streaming of agent state, model tokens, tool outputs, or combined streams.
- [**Deployment tooling**](./deployment.md): Includes infrastructure-free deployment tools. [**LangGraph Platform**](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform/) supports testing, debugging, and deployment.
- **[Studio](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio/)**: A visual IDE for inspecting and debugging workflows.
- Supports multiple [**deployment options**](https://langchain-ai.github.io/langgraph/concepts/deployment_options.md) for production.
- [**Deployment tooling**](../tutorials/langgraph-platform/local-server.md): Includes infrastructure-free deployment tools. [**LangGraph Platform**](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform/) supports testing, debugging, and deployment.
- **[Studio](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio/)**: A visual IDE for inspecting and debugging workflows.
- Supports multiple [**deployment options**](https://langchain-ai.github.io/langgraph/concepts/deployment_options.md) for production.
## High-level building blocks
@@ -40,30 +40,32 @@ LangGraph comes with a set of prebuilt components that implement common agent be
Using LangGraph for agent development allows you to focus on your application's logic and behavior, instead of building and maintaining the supporting infrastructure for state, memory, and human feedback.
:::python
## Package ecosystem
The high-level components are organized into several packages, each with a specific focus.
It allows you to explore the infrastructure of the agent as defined by the presence of:
* [`tools`](../agents/tools.md): A list of tools (functions, APIs, or other callable objects) that the agent can use to perform tasks.
* [`pre_model_hook`](../how-tos/create-react-agent-manage-message-history.ipynb): A function that is called before the model is invoked. It can be used to condense messages or perform other preprocessing tasks.
*`post_model_hook`: A function that is called after the model is invoked. It can be used to implement guardrails, human-in-the-loop flows, or other postprocessing tasks.
* [`response_format`](../agents/agents.md#6-configure-structured-output): A data structure used to constrain the type of the final output, e.g., a `pydantic``BaseModel`.
- [`tools`](../how-tos/tool-calling.md): A list of tools (functions, APIs, or other callable objects) that the agent can use to perform tasks.
- [`pre_model_hook`](../how-tos/create-react-agent-manage-message-history.ipynb): A function that is called before the model is invoked. It can be used to condense messages or perform other preprocessing tasks.
-`post_model_hook`: A function that is called after the model is invoked. It can be used to implement guardrails, human-in-the-loop flows, or other postprocessing tasks.
- [`response_format`](../agents/agents.md#6-configure-structured-output): A data structure used to constrain the type of the final output, e.g., a `pydantic``BaseModel`.
<div class="agent-layout">
<div class="agent-graph-features-container">
@@ -82,15 +84,13 @@ It allows you to explore the infrastructure of the agent as defined by the prese
</div>
</div>
The following code snippet shows how to create the above agent (and underlying graph) with
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");
}
@@ -189,3 +189,159 @@ function initializeWidget() {
Use the following tool to visualize the graph generated by @[`createReactAgent`][create_react_agent] and to view an outline of the corresponding code. It allows you to explore the infrastructure of the agent as defined by the presence of:
- [`tools`](./tools.md): A list of tools (functions, APIs, or other callable objects) that the agent can use to perform tasks.
-`preModelHook`: A function that is called before the model is invoked. It can be used to condense messages or perform other preprocessing tasks.
-`postModelHook`: A function that is called after the model is invoked. It can be used to implement guardrails, human-in-the-loop flows, or other postprocessing tasks.
- [`responseFormat`](./agents.md#6-configure-structured-output): A data structure used to constrain the type of the final output (via Zod schemas).
| **trustcall** | [hinthornw/trustcall](https://github.com/hinthornw/trustcall) | Tenacious tool calling built on LangGraph. | -12345 | 
| **breeze-agent** | [andrestorres123/breeze-agent](https://github.com/andrestorres123/breeze-agent) | A streamlined research system built inspired on STORM and built on LangGraph. | -12345 | 
| **langgraph-supervisor** | [langchain-ai/langgraph-supervisor-py](https://github.com/langchain-ai/langgraph-supervisor-py) | Build supervisor multi-agent systems with LangGraph. | -12345 | 
| **langmem** | [langchain-ai/langmem](https://github.com/langchain-ai/langmem) | Build agents that learn and adapt from interactions over time. | -12345 | 
| **langchain-mcp-adapters** | [langchain-ai/langchain-mcp-adapters](https://github.com/langchain-ai/langchain-mcp-adapters) | Make Anthropic Model Context Protocol (MCP) tools compatible with LangGraph agents. | -12345 | 
| **open-deep-research** | [langchain-ai/open_deep_research](https://github.com/langchain-ai/open_deep_research) | Open source assistant for iterative web research and report writing. | -12345 | 
| **langgraph-swarm** | [langchain-ai/langgraph-swarm-py](https://github.com/langchain-ai/langgraph-swarm-py) | Build swarm-style multi-agent systems using LangGraph. | -12345 | 
| **delve-taxonomy-generator** | [andrestorres123/delve](https://github.com/andrestorres123/delve) | A taxonomy generator for unstructured data | -12345 | 
| **nodeology** | [xyin-anl/Nodeology](https://github.com/xyin-anl/Nodeology) | Enable researcher to build scientific workflows easily with simplified interface. | -12345 | 
| **langgraph-bigtool** | [langchain-ai/langgraph-bigtool](https://github.com/langchain-ai/langgraph-bigtool) | Build LangGraph agents with large numbers of tools. | -12345 | 
| **ai-data-science-team** | [business-science/ai-data-science-team](https://github.com/business-science/ai-data-science-team) | An AI-powered data science team of agents to help you perform common data science tasks 10X faster. | -12345 | 
| **langgraph-reflection** | [langchain-ai/langgraph-reflection](https://github.com/langchain-ai/langgraph-reflection) | LangGraph agent that runs a reflection step. | -12345 | 
| **langgraph-codeact** | [langchain-ai/langgraph-codeact](https://github.com/langchain-ai/langgraph-codeact) | LangGraph implementation of CodeAct agent that generates and executes code instead of tool calling. | -12345 | 
| **trustcall** | https://github.com/hinthornw/trustcall | Tenacious tool calling built on LangGraph. | -12345 | 
| **breeze-agent** | https://github.com/andrestorres123/breeze-agent | A streamlined research system built inspired on STORM and built on LangGraph. | -12345 | 
| **langgraph-supervisor** | https://github.com/langchain-ai/langgraph-supervisor-py | Build supervisor multi-agent systems with LangGraph. | -12345 | 
| **langmem** | https://github.com/langchain-ai/langmem | Build agents that learn and adapt from interactions over time. | -12345 | 
| **langchain-mcp-adapters** | https://github.com/langchain-ai/langchain-mcp-adapters | Make Anthropic Model Context Protocol (MCP) tools compatible with LangGraph agents. | -12345 | 
| **open-deep-research** | https://github.com/langchain-ai/open_deep_research | Open source assistant for iterative web research and report writing. | -12345 | 
| **langgraph-swarm** | https://github.com/langchain-ai/langgraph-swarm-py | Build swarm-style multi-agent systems using LangGraph. | -12345 | 
| **delve-taxonomy-generator** | https://github.com/andrestorres123/delve | A taxonomy generator for unstructured data | -12345 | 
| **nodeology** | https://github.com/xyin-anl/Nodeology | Enable researcher to build scientific workflows easily with simplified interface. | -12345 | 
| **langgraph-bigtool** | https://github.com/langchain-ai/langgraph-bigtool | Build LangGraph agents with large numbers of tools. | -12345 | 
| **ai-data-science-team** | https://github.com/business-science/ai-data-science-team | An AI-powered data science team of agents to help you perform common data science tasks 10X faster. | -12345 | 
| **langgraph-reflection** | https://github.com/langchain-ai/langgraph-reflection | LangGraph agent that runs a reflection step. | -12345 | 
| **langgraph-codeact** | https://github.com/langchain-ai/langgraph-codeact | LangGraph implementation of CodeAct agent that generates and executes code instead of tool calling. | -12345 | 
## ✨ Contributing Your Library
@@ -32,13 +33,41 @@ To share your project, simply open a Pull Request adding an entry for your packa
**Guidelines**
- Your repo must be distributed as an installable package (e.g., PyPI for Python, npm
for JavaScript/TypeScript, etc.) 📦
- Your repo must be distributed as an installable package on PyPI 📦
- The repo should either use the Graph API (exposing a `StateGraph` instance) or
the Functional API (exposing an `entrypoint`).
- The package must include documentation (e.g., a `README.md` or docs site)
| **@langchain/langgraph-cua** | https://github.com/langchain-ai/langgraphjs/tree/main/libs/langgraph-cua | Build computer use agents with LangGraph | -12345 | 
## ✨ Contributing Your Library
Have you built an awesome open-source library using LangGraph? We'd love to feature
your project on the official LangGraph documentation pages! 🏆
To share your project, simply open a Pull Request adding an entry for your package in our [packages.yml](https://github.com/langchain-ai/langgraph/blob/main/docs/_scripts/third_party_page/packages.yml) file.
**Guidelines**
- Your repo must be distributed as an installable package on npm 📦
- The repo should either use the Graph API (exposing a `StateGraph` instance) or
the Functional API (exposing an `entrypoint`).
- The package must include documentation (e.g., a `README.md` or docs site)
Agents support both synchronous and asynchronous execution using either `.invoke()` / `await .ainvoke()` for full responses, or `.stream()` / `.astream()` for **incremental** [streaming](../how-tos/streaming.md) output. This section explains how to provide input, interpret output, enable streaming, and control execution limits.
## Basic usage
Agents can be executed in two primary modes:
:::python
- **Synchronous** using `.invoke()` or `.stream()`
- **Asynchronous** using `await .ainvoke()` or `async for` with `.astream()`
:::
:::js
- **Synchronous** using `.invoke()` or `.stream()`
- **Asynchronous** using `await .invoke()` or `for await` with `.stream()`
:::
:::python
=== "Sync invocation"
```python
from langgraph.prebuilt import create_react_agent
@@ -31,6 +40,7 @@ Agents can be executed in two primary modes:
```
=== "Async invocation"
```python
from langgraph.prebuilt import create_react_agent
@@ -39,6 +49,24 @@ Agents can be executed in two primary modes:
response = await agent.ainvoke({"messages": [{"role": "user", "content": "what is the weather in sf"}]})
```
:::
:::js
```typescript
import { createReactAgent } from "@langchain/langgraph/prebuilt";
const agent = createReactAgent(...);
// highlight-next-line
const response = await agent.invoke({
"messages": [
{ "role": "user", "content": "what is the weather in sf" }
]
});
```
:::
## Inputs and outputs
Agents use a language model that expects a list of `messages` as an input. Therefore, agent inputs and outputs are stored as a list of `messages` under the `messages` key in the agent [state](../concepts/low_level.md#working-with-messages-in-graph-state).
@@ -47,33 +75,73 @@ Agents use a language model that expects a list of `messages` as an input. There
Agent input must be a dictionary with a `messages` key. Supported formats are:
| List of messages | `{"messages": [{"role": "user", "content": "Hello"}]}` |
| With custom state | `{"messages": [{"role": "user", "content": "Hello"}], "user_name": "Alice"}` — If using a custom state definition |
:::
:::python
Messages are automatically converted into LangChain's internal message format. You can read
more about [LangChain messages](https://python.langchain.com/docs/concepts/messages/#langchain-messages) in the LangChain documentation.
:::
:::js
Messages are automatically converted into LangChain's internal message format. You can read
more about [LangChain messages](https://js.langchain.com/docs/concepts/messages/#langchain-messages) in the LangChain documentation.
:::
!!! tip "Using custom agent state"
You can provide additional fields defined in your agent’s state schema directly in the input dictionary. This allows dynamic behavior based on runtime data or prior tool outputs.
:::python
You can provide additional fields defined in your agent's state schema directly in the input dictionary. This allows dynamic behavior based on runtime data or prior tool outputs.
See the [context guide](./context.md) for full details.
:::
:::js
You can provide additional fields defined in your agent's state directly in the state definition. This allows dynamic behavior based on runtime data or prior tool outputs.
See the [context guide](./context.md) for full details.
:::
!!! note
:::python
A string input for `messages` is converted to a [HumanMessage](https://python.langchain.com/docs/concepts/messages/#humanmessage). This behavior differs from the `prompt` parameter in `create_react_agent`, which is interpreted as a [SystemMessage](https://python.langchain.com/docs/concepts/messages/#systemmessage) when passed as a string.
:::
:::js
A string input for `messages` is converted to a [HumanMessage](https://js.langchain.com/docs/concepts/messages/#humanmessage). This behavior differs from the `prompt` parameter in `createReactAgent`, which is interpreted as a [SystemMessage](https://js.langchain.com/docs/concepts/messages/#systemmessage) when passed as a string.
:::
## Output format
:::python
Agent output is a dictionary containing:
- `messages`: A list of all messages exchanged during execution (user input, assistant replies, tool invocations).
- Optionally, `structured_response` if [structured output](./agents.md#6-configure-structured-output) is configured.
- If using a custom `state_schema`, additional keys corresponding to your defined fields may also be present in the output. These can hold updated state values from tool execution or prompt logic.
:::
:::js
Agent output is a dictionary containing:
- `messages`: A list of all messages exchanged during execution (user input, assistant replies, tool invocations).
- Optionally, `structuredResponse` if [structured output](./agents.md#6-configure-structured-output) is configured.
- If using a custom state definition, additional keys corresponding to your defined fields may also be present in the output. These can hold updated state values from tool execution or prompt logic.
:::
See the [context guide](./context.md) for more details on working with custom state schemas and accessing context.
@@ -87,6 +155,7 @@ Agents support streaming responses for more responsive applications. This includ
Streaming is available in both sync and async modes:
:::python
=== "Sync streaming"
```python
@@ -107,14 +176,36 @@ Streaming is available in both sync and async modes:
print(chunk)
```
:::
:::js
```typescript
for await (const chunk of agent.stream(
{ messages: [{ role: "user", content: "what is the weather in sf" }] },
{ streamMode: "updates" }
)) {
console.log(chunk);
}
```
:::
!!! tip
For full details, see the [streaming guide](../how-tos/streaming.md).
## Max iterations
:::python
To control agent execution and avoid infinite loops, set a recursion limit. This defines the maximum number of steps the agent can take before raising a `GraphRecursionError`. You can configure `recursion_limit` at runtime or when defining agent via `.with_config()`:
:::
:::js
To control agent execution and avoid infinite loops, set a recursion limit. This defines the maximum number of steps the agent can take before raising a `GraphRecursionError`. You can configure `recursionLimit` at runtime or when defining agent via `.withConfig()`:
:::
:::python
=== "Runtime"
```python
@@ -163,6 +254,70 @@ To control agent execution and avoid infinite loops, set a recursion limit. This
print("Agent stopped due to max iterations.")
```
:::
:::js
=== "Runtime"
```typescript
import { GraphRecursionError } from "@langchain/langgraph";
import { ChatAnthropic } from "@langchain/langgraph/prebuilt";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
const maxIterations = 3;
// highlight-next-line
const recursionLimit = 2 * maxIterations + 1;
const agent = createReactAgent({
llm: new ChatAnthropic({ model: "claude-3-5-haiku-latest" }),
tools: [getWeather]
});
try {
const response = await agent.invoke(
{"messages": [{"role": "user", "content": "what's the weather in sf"}]},
// highlight-next-line
{ recursionLimit }
);
} catch (error) {
if (error instanceof GraphRecursionError) {
console.log("Agent stopped due to max iterations.");
}
}
```
=== "`.withConfig()`"
```typescript
import { GraphRecursionError } from "@langchain/langgraph";
import { ChatAnthropic } from "@langchain/langgraph/prebuilt";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
const maxIterations = 3;
// highlight-next-line
const recursionLimit = 2 * maxIterations + 1;
const agent = createReactAgent({
llm: new ChatAnthropic({ model: "claude-3-5-haiku-latest" }),
[Tools](https://python.langchain.com/docs/concepts/tools/) are a way to encapsulate a function and its input schema in a way that can be passed to a chat model that supports tool calling. This allows the model to request the execution of this function with specific inputs.
You can either [define your own tools](#define-simple-tools) or use [prebuilt integrations](#prebuilt-tools) that LangChain provides.
## Define simple tools
You can pass a vanilla function to `create_react_agent` to use as a tool:
```python
fromlanggraph.prebuiltimportcreate_react_agent
defmultiply(a:int,b:int)->int:
"""Multiply two numbers."""
returna*b
create_react_agent(
model="anthropic:claude-3-7-sonnet",
tools=[multiply]
)
```
`create_react_agent` automatically converts vanilla functions to [LangChain tools](https://python.langchain.com/docs/concepts/tools/#tool-interface).
## Customize tools
For more control over tool behavior, use the `@tool` decorator:
```python
# highlight-next-line
fromlangchain_core.toolsimporttool
# highlight-next-line
@tool("multiply_tool",parse_docstring=True)
defmultiply(a:int,b:int)->int:
"""Multiply two numbers.
Args:
a: First operand
b: Second operand
"""
returna*b
```
You can also define a custom input schema using Pydantic:
{"messages":[{"role":"user","content":"Hi, I am Bob"}]}
)
```
!!! Warning "Avoid infinite loops"
Forcing tool usage without stopping conditions can create infinite loops. Use one of the following safeguards:
- Mark the tool with [`return_direct=True`](#return-tool-results-directly) to end the loop after execution.
- Set [`recursion_limit`](../concepts/low_level.md#recursion-limit) to restrict the number of execution steps.
## Handle tool errors
By default, the agent will catch all exceptions raised during tool calls and will pass those as tool messages to the LLM. To control how the errors are handled, you can use the prebuilt [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode] — the node that executes tools inside `create_react_agent` — via its `handle_tool_errors` parameter:
=== "Enable error handling (default)"
```python
from langgraph.prebuilt import create_react_agent
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
if a == 42:
raise ValueError("The ultimate error")
return a * b
# Run with error handling (default)
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[multiply]
)
agent.invoke(
{"messages": [{"role": "user", "content": "what's 42 x 7?"}]}
)
```
=== "Disable error handling"
```python
from langgraph.prebuilt import create_react_agent, ToolNode
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
if a == 42:
raise ValueError("The ultimate error")
return a * b
# highlight-next-line
tool_node = ToolNode(
[multiply],
# highlight-next-line
handle_tool_errors=False # (1)!
)
agent_no_error_handling = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=tool_node
)
agent_no_error_handling.invoke(
{"messages": [{"role": "user", "content": "what's 42 x 7?"}]}
)
```
1. This disables error handling (enabled by default). See all available strategies in the [API reference][langgraph.prebuilt.tool_node.ToolNode].
=== "Custom error handling"
```python
from langgraph.prebuilt import create_react_agent, ToolNode
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
if a == 42:
raise ValueError("The ultimate error")
return a * b
# highlight-next-line
tool_node = ToolNode(
[multiply],
# highlight-next-line
handle_tool_errors=(
"Can't use 42 as a first operand, you must switch operands!" # (1)!
)
)
agent_custom_error_handling = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=tool_node
)
agent_custom_error_handling.invoke(
{"messages": [{"role": "user", "content": "what's 42 x 7?"}]}
)
```
1. This provides a custom message to send to the LLM in case of an exception. See all available strategies in the [API reference][langgraph.prebuilt.tool_node.ToolNode].
See [API reference][langgraph.prebuilt.tool_node.ToolNode] for more information on different tool error handling options.
## Working with memory
LangGraph allows access to short-term and long-term memory from tools. See [Memory](../how-tos/memory/add-memory.md) guide for more information on:
* how to [read](../how-tos/memory/add-memory.md#read-short-term) from and [write](../how-tos/memory/add-memory.md#write-short-term) to **short-term** memory
* how to [read](../how-tos/memory/add-memory.md#read-long-term) from and [write](../how-tos/memory/add-memory.md#write-long-term) to **long-term** memory
## Prebuilt tools
You can use prebuilt tools from model providers by passing a dictionary with tool specs to the `tools` parameter of `create_react_agent`. For example, to use the `web_search_preview` tool from OpenAI:
```python
from langgraph.prebuilt import create_react_agent
agent = create_react_agent(
model="openai:gpt-4o-mini",
tools=[{"type": "web_search_preview"}]
)
response = agent.invoke(
{"messages": ["What was a positive news story from today?"]}
)
```
Additionally, LangChain supports a wide range of prebuilt tool integrations for interacting with APIs, databases, file systems, web data, and more. These tools extend the functionality of agents and enable rapid development.
You can browse the full list of available integrations in the [LangChain integrations directory](https://python.langchain.com/docs/integrations/tools/).
@@ -13,7 +13,7 @@ You can use a prebuilt chat UI for interacting with any LangGraph agent through
## Run agent in UI
First, set up LangGraph API server [locally](./deployment.md#launch-langgraph-server-locally) or deploy your agent on [LangGraph Platform](https://langchain-ai.github.io/langgraph/cloud/quick_start/).
First, set up LangGraph API server [locally](../tutorials/langgraph-platform/local-server.md) or deploy your agent on [LangGraph Platform](https://langchain-ai.github.io/langgraph/cloud/quick_start/).
Then, navigate to [Agent Chat UI](https://agentchat.vercel.app), or clone the repository and [run the dev server locally](https://github.com/langchain-ai/agent-chat-ui?tab=readme-ov-file#setup):
@@ -25,13 +25,13 @@ Then, navigate to [Agent Chat UI](https://agentchat.vercel.app), or clone the re
## Add human-in-the-loop
Agent Chat UI has full support for [human-in-the-loop](../concepts/human_in_the_loop.md) workflows. To try it out, replace the agent code in `src/agent/graph.py` (from the [deployment](./deployment.md) guide) with this [agent implementation](../how-tos/human_in_the_loop/add-human-in-the-loop.md#add-interrupts-to-any-tool):
Agent Chat UI has full support for [human-in-the-loop](../concepts/human_in_the_loop.md) workflows. To try it out, replace the agent code in `src/agent/graph.py` (from the [deployment](../tutorials/langgraph-platform/local-server.md) guide) with this [agent implementation](../how-tos/human_in_the_loop/add-human-in-the-loop.md#add-interrupts-to-any-tool):
Agent Chat UI works best if your LangGraph agent interrupts using the [`HumanInterrupt` schema][langgraph.prebuilt.interrupt.HumanInterrupt]. If you do not use that schema, the Agent Chat UI will be able to render the input passed to the `interrupt` function, but it will not have full support for resuming your graph.
Agent Chat UI works best if your LangGraph agent interrupts using the @[`HumanInterrupt` schema][HumanInterrupt]. If you do not use that schema, the Agent Chat UI will be able to render the input passed to the `interrupt` function, but it will not have full support for resuming your graph.
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.
A thread contains the accumulated state of a sequence of [runs](../../concepts/assistants.md#execution). When a run is executed, the [state](../../concepts/low_level.md#state) of the underlying graph of the assistant will be persisted to the thread.
A thread's current and historical state can be retrieved. To persist state, a thread must be created prior to executing a run.
The state of a thread at a particular point in time is called a [checkpoint](../../concepts/persistence.md#checkpoints). Checkpoints are persisted and can be used to restore the state of a thread at a later time.
## Learn more
* For more on threads and checkpoints, see this section of the [LangGraph conceptual guide](../../concepts/persistence.md).
* The LangGraph Platform API provides several endpoints for creating and managing threads and thread state. See the [API reference](../../cloud/reference/api/api_ref.html#tag/threads) for more details.
@@ -99,8 +99,8 @@ 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 not trigger subsequent updates. In the future, this functionality may be changed/improved.
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.
# 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)
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.
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 is currently in beta stage and requires an [Enterprise](../../concepts/plans.md) plan.
The Self-Hosted Control Plane deployment option requires an [Enterprise](../../concepts/plans.md) plan.
## Prerequisites
@@ -23,6 +23,8 @@ Before deploying, review the [conceptual guide for the Self-Hosted Control Plane
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.
Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each [CompiledStateGraph][langgraph.graph.state.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).
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):
@@ -108,11 +108,11 @@ from langgraph.graph import StateGraph, END, START
Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each [CompiledStateGraph][langgraph.graph.state.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).
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):
@@ -121,11 +121,11 @@ from langgraph.graph import StateGraph, END, START
@@ -21,9 +21,9 @@ Before deploying, review the [conceptual guide for the Standalone Container](../
`<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.`LANGSMITH_API_KEY`: (if using [Lite](../../concepts/langgraph_server.md#server-versions)) LangSmith API key. This will be used to authenticate ONCE at server start up.
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.
@@ -305,6 +301,185 @@ To review, edit, and approve tool calls in an agent or workflow, use LangGraph's
}"
```
## 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.
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 configurations, consider the following simple `call_model` node and configuration schema. Observe that this node tries to read and use the `model_name` as defined by the `config` object's `configurable`.
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.
# We return a list, because this will get added to the existing list
return {"messages": [response]}
@@ -44,7 +43,9 @@ First, as a brief refresher on the concept of configurations, consider the follo
}
```
For more information on configurations, [see here](../../concepts/low_level.md#configuration).
:::python
For more information on runtime context, [see here](../../concepts/low_level.md#runtime-context).
:::
## Create an assistant
@@ -328,4 +329,4 @@ If you now run your graph and pass in this assistant id, it will use the first v
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.
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.
Next, define your UI components in your `langgraph.json` configuration:
```json
{
"node_version": "20",
"graphs": {
"agent": "./src/agent/index.ts:graph"
},
"ui": {
"agent": "./src/agent/ui.tsx"
}
}
```
=== "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.
[Breakpoints](../../concepts/breakpoints.md) pause graph execution at defined points and let you step through each stage. They use LangGraph's [**persistence layer**](../../concepts/persistence.md), which saves the graph state after each step.
With breakpoints, you can inspect the graph's state and node inputs at any point. Execution pauses indefinitely until you resume, as the checkpointer preserves the state.
!!! tip
For conceptual information on breakpoints, see [Breakpoints](../../concepts/breakpoints.md).
## Set static breakpoints
Static breakpoints are triggered either before or after a node executes. You can set static breakpoints by specifying `interrupt_before` and `interrupt_after` at compile time or run time.
=== "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.
=== "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.
This example shows how to add **static** breakpoints. See [Use breakpoints](../../how-tos/human_in_the_loop/breakpoints.md) for more options on adding breakpoints.
=== "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.
@@ -4,11 +4,11 @@ LangGraph provides the [**time travel**](../../concepts/time-travel.md) function
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`][langgraph_sdk.client.RunsClient.wait] or [`client.runs.stream`][langgraph_sdk.client.RunsClient.stream] APIs.
2.**Identify a checkpoint in an existing thread**: Use [`client.threads.get_history`][langgraph_sdk.client.ThreadsClient.get_history] method to retrieve the execution history for a specific `thread_id` and locate the desired `checkpoint_id`.
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`][langgraph_sdk.client.ThreadsClient.update_state] method to modify the graph’s state at the checkpoint and resume execution from alternative state.
4.**Resume execution from the checkpoint**: Use the [`client.runs.wait`][langgraph_sdk.client.RunsClient.wait] or [`client.runs.stream`][langgraph_sdk.client.RunsClient.stream] APIs with an input of `None` and the appropriate `thread_id` and `checkpoint_id`.
3.**(Optional) modify the graph state**: Use the @[`client.threads.update_state`][client.threads.update_state] method to modify the graph’s 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`.
@@ -29,7 +29,7 @@ Click the dropdown next to "Submit" and click the toggle to enable/disable strea
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/breakpoints.md).
For more information on breakpoints see [here](../../concepts/human_in_the_loop.md).
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.
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.
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.
Your server should extract and validate this token before processing requests.
## Disable webhooks
As of `langgraph-api>=0.2.78`, developers can disable webhooks in the `langgraph.json` file:
```json
{
"http": {
"disable_webhooks": true
}
}
```
This feature is primarily intended for self-hosted deployments, where platform administrators or developers may prefer to disable webhooks to simplify their security posture—especially if they are not configuring firewall rules or other network controls. Disabling webhooks helps prevent untrusted payloads from being sent to internal endpoints.
For full configuration details, refer to the [configuration file reference](https://langchain-ai.github.io/langgraph/cloud/reference/cli/?h=disable_webhooks#configuration-file).
## Test webhooks
You can test your webhook using online services like:
The LangGraph Platform API reference is available with each deployment at the `/docs`URL path (e.g. `http://localhost:8124/docs`).
The LangGraph Server API reference is available within each deployment at the `/docs`endpoint (e.g. `http://localhost:8124/docs`).
Click <a href="/langgraph/cloud/reference/api/api_ref.html" target="_blank">here</a> to view the API reference.
## Authentication
For deployments to LangGraph Platform, authentication is required. Pass the `X-Api-Key` header with each request to the LangGraph Platform API. The value of the header should be set to a valid LangSmith API key for the organization where the API is deployed.
For deployments to LangGraph Platform, authentication is required. Pass the `X-Api-Key` header with each request to the LangGraph Server. The value of the header should be set to a valid LangSmith API key for the organization where the LangGraph Server is deployed.
The LangGraph Control Plane API is used to programmatically create and manage LangGraph Server deployments. For example, the APIs can be orchestrated to create custom CI/CD workflows.
Click <a href="https://api.host.langchain.com/docs" target="_blank">here</a> to view the API reference.
## Host
LangGraph Control Plane hosts for Cloud SaaS data regions:
**Note**: Self-hosted deployments of LangGraph Platform will have a custom host for the LangGraph Control Plane.
## Authentication
To authenticate with the LangGraph Control Plane API, set the `X-Api-Key` header to a valid LangSmith API key.
Example `curl` command:
```shell
curl --request GET \
--url http://localhost:8124/v2/deployments \
--header 'X-Api-Key: LANGSMITH_API_KEY'
```
## Versioning
Each endpoint path is prefixed with a version (e.g. `v1`, `v2`).
## Quick Start
1. Call `POST /v2/deployments` to create a new Deployment. The response body contains the Deployment ID (`id`) and the ID of the latest (and first) revision (`latest_revision_id`).
1. Call `GET /v2/deployments/{deployment_id}` to retrieve the Deployment. Set `deployment_id` in the URL to the value of Deployment ID (`id`).
1. Poll for revision `status` until `status` is `DEPLOYED` by calling `GET /v2/deployments/{deployment_id}/revisions/{latest_revision_id}`.
1. Call `PATCH /v2/deployments/{deployment_id}` to update the deployment.
## Example Code
Below is example Python code that demonstrates how to orchestrate the LangGraph Control Plane APIs to create a deployment, update the deployment, and delete the deployment.
| <span style="white-space: nowrap;">`pip_installer`</span> | _(Added in v0.3)_ Optional. Python package installer selector. It can be set to `"auto"`, `"pip"`, or `"uv"`. From version 0.3 onward the default strategy is to run `uv pip`, which typically delivers faster builds while remaining a drop-in replacement. In the uncommon situation where `uv` cannot handle your dependency graph or the structure of your `pyproject.toml`, specify `"pip"` here to revert to the earlier behaviour. |
| <span style="white-space: nowrap;">`keep_pkg_tools`</span> | _(Added in v0.3.4)_ Optional. Control whether to retain Python packaging tools (`pip`, `setuptools`, `wheel`) in the final image. Accepted values: <ul><li><code>true</code> : Keep all three tools (skip uninstall).</li><li><code>false</code> / omitted : Uninstall all three tools (default behaviour).</li><li><code>list[str]</code> : Names of tools <strong>to retain</strong>. Each value must be one of "pip", "setuptools", "wheel".</li></ul>. By default, all three tools are uninstalled. |
| <span style="white-space: nowrap;">`dockerfile_lines`</span> | Array of additional lines to add to Dockerfile following the import from parent image. |
| <span style="white-space: nowrap;">`checkpointer`</span> | Configuration for the checkpointer. Contains a `ttl` field which is an object with the following keys: <ul><li>`strategy`: How to handle expired checkpoints (e.g., `"delete"`).</li><li>`sweep_interval_minutes`: How often to check for expired checkpoints (integer).</li><li>`default_ttl`: Default time-to-live for checkpoints in **minutes** (integer). Defines how long checkpoints are kept before the specified strategy is applied.</li></ul> |
| <span style="white-space: nowrap;">`http`</span> | HTTP server configuration with the following fields: <ul><li>`app`: Path to custom Starlette/FastAPI app (e.g., `"./src/agent/webapp.py:app"`). See [custom routes guide](../../how-tos/http/custom_routes.md).</li><li>`disable_assistants`: Disable `/assistants` routes</li><li>`disable_threads`: Disable `/threads` routes</li><li>`disable_runs`: Disable `/runs` routes</li><li>`disable_store`: Disable `/store` routes</li><li>`disable_meta`: Disable `/ok`, `/info`, `/metrics`, and `/docs` routes</li><li>`disable_mcp`: Disable `/mcp` routes</li><li>`cors`: CORS configuration with fields for `allow_origins`, `allow_methods`, `allow_headers`, etc.</li><li>`configurable_headers`: Define which request headers to exclude or include as a run's configurable values.</li></ul> |
| <span style="white-space: nowrap;">`http`</span> | HTTP server configuration with the following fields: <ul><li>`app`: Path to custom Starlette/FastAPI app (e.g., `"./src/agent/webapp.py:app"`). See [custom routes guide](../../how-tos/http/custom_routes.md).</li><li>`cors`: CORS configuration with fields for `allow_origins`, `allow_methods`, `allow_headers`, etc.</li><li>`configurable_headers`: Define which request headers to exclude or include as a run's configurable values.</li><li>`disable_assistants`: Disable `/assistants` routes</li><li>`disable_mcp`: Disable `/mcp` routes</li><li>`disable_meta`: Disable `/ok`, `/info`, `/metrics`, and `/docs` routes</li><li>`disable_runs`: Disable `/runs` routes</li><li>`disable_store`: Disable `/store` routes</li><li>`disable_threads`: Disable `/threads` routes</li><li>`disable_ui`: Disable `/ui` routes</li><li>`disable_webhooks`: Disable webhooks calls on run completion in all routes</li><li>`mount_prefix`: Prefix for mounted routes (e.g., "/my-deployment/api")</li></ul> |
=== "JS"
@@ -395,7 +396,7 @@ The LangGraph CLI requires a JSON configuration file that follows this [schema](
=== "Python"
Start LangGraph API server. For local testing, requires a LangSmith API key with access to LangGraph Platform closed beta. Requires a license key for production use.
Start LangGraph API server. For local testing, requires a LangSmith API key with access to LangGraph Platform. Requires a license key for production use.
**Usage**
@@ -408,6 +409,8 @@ The LangGraph CLI requires a JSON configuration file that follows this [schema](
| `--wait` | | Wait for services to start before returning. Implies --detach |
| `--base-image TEXT` | `langchain/langgraph-api` | Base image to use for the LangGraph API server. Pin to specific versions using version tags. |
| `--image TEXT` | | Docker image to use for the langgraph-api service. If specified, skips building and uses this image directly. |
| `--postgres-uri TEXT` | Local database | Postgres URI to use for the database. |
| `--watch` | | Restart on file changes |
| `--debugger-base-url TEXT` | `http://127.0.0.1:[PORT]` | URL used by the debugger to access LangGraph API. |
@@ -422,7 +425,7 @@ The LangGraph CLI requires a JSON configuration file that follows this [schema](
=== "JS"
Start LangGraph API server. For local testing, requires a LangSmith API key with access to LangGraph Platform closed beta. Requires a license key for production use.
Start LangGraph API server. For local testing, requires a LangSmith API key with access to LangGraph Platform. Requires a license key for production use.
**Usage**
@@ -435,6 +438,8 @@ The LangGraph CLI requires a JSON configuration file that follows this [schema](
| <span style="white-space: nowrap;">`--wait`</span> | | Wait for services to start before returning. Implies --detach |
| <span style="white-space: nowrap;">`--base-image TEXT`</span> | <span style="white-space: nowrap;">`langchain/langgraph-api`</span> | Base image to use for the LangGraph API server. Pin to specific versions using version tags. |
| <span style="white-space: nowrap;">`--image TEXT`</span> | | Docker image to use for the langgraph-api service. If specified, skips building and uses this image directly. |
| <span style="white-space: nowrap;">`--postgres-uri TEXT`</span> | Local database | Postgres URI to use for the database. |
@@ -10,6 +10,10 @@ This environment variable should be set to `True` if the implementation of a gra
Defaults to `False`.
## `BG_JOB_SHUTDOWN_GRACE_PERIOD_SECS`
Specifies, in seconds, how long the server will wait for background jobs to finish after the queue receives a shutdown signal. After this period, the server will force termination. Defaults to `180` seconds. Set this to ensure jobs have enough time to complete cleanly during shutdown. Added in `langgraph-api==0.2.16`.
## `BG_JOB_TIMEOUT_SECS`
The timeout of a background run can be increased. However, the infrastructure for a Cloud SaaS deployment enforces a 1 hour timeout limit for API requests. This means the connection between client and server will timeout after 1 hour. This is not configurable.
@@ -18,16 +22,15 @@ A background run can execute for longer than 1 hour, but a client must reconnect
Defaults to `3600`.
## `BG_JOB_SHUTDOWN_GRACE_PERIOD_SECS`
Specifies, in seconds, how long the server will wait for background jobs to finish after the queue receives a shutdown signal. After this period, the server will force termination. Defaults to `3600` seconds. Set this to ensure jobs have enough time to complete cleanly during shutdown. Added in `langgraph-api==0.2.16`.
## `DD_API_KEY`
Specify `DD_API_KEY` (your [Datadog API Key](https://docs.datadoghq.com/account_management/api-app-keys/)) to automatically enable Datadog tracing for the deployment. Specify other [`DD_*` environment variables](https://ddtrace.readthedocs.io/en/stable/configuration.html) to configure the tracing instrumentation.
If `DD_API_KEY` is specified, the application process is wrapped in the [`ddtrace-run` command](https://ddtrace.readthedocs.io/en/stable/installation_quickstart.html). Other `DD_*` environment variables (e.g. `DD_SITE`, `DD_ENV`, `DD_SERVICE`, `DD_TRACE_ENABLED`) are typically needed to properly configure the tracing instrumentation. See [`DD_*` environment variables](https://ddtrace.readthedocs.io/en/stable/configuration.html) for more details.
!!! note
Enabling `DD_API_KEY` (and thus `ddtrace-run`) can override or interfere with other auto-instrumentation solutions (such as OpenTelemetry) that you may have instrumented into your application code.
## `LANGCHAIN_TRACING_SAMPLING_RATE`
Sampling rate for traces sent to LangSmith. Valid values: Any float between `0` and `1`.
@@ -40,6 +43,14 @@ Type of authentication for the LangGraph Server deployment. Valid values: `langs
For deployments to LangGraph Platform, this environment variable is set automatically. For local development or deployments where authentication is handled externally (e.g. self-hosted), set this environment variable to `noop`.
## `LANGGRAPH_POSTGRES_POOL_MAX_SIZE`
Beginning with langgraph-api version `0.2.12`, the maximum size of the Postgres connection pool (per replica) can be controlled using the `LANGGRAPH_POSTGRES_POOL_MAX_SIZE` environment variable. By setting this variable, you can determine the upper bound on the number of simultaneous connections the server will establish with the Postgres database.
For example, if a deployment is scaled up to 10 replicas and `LANGGRAPH_POSTGRES_POOL_MAX_SIZE` is configured to `150`, then up to `1500` connections to Postgres can be established. This is particularly useful for deployments where database resources are limited (or more available) or where you need to tune connection behavior for performance or scaling reasons.
Defaults to `150` connections.
## `LANGSMITH_RUNS_ENDPOINTS`
For deployments with [self-hosted LangSmith](https://docs.smith.langchain.com/self_hosting) only.
@@ -54,6 +65,10 @@ Set `LANGSMITH_TRACING` to `false` to disable tracing to LangSmith.
Defaults to `true`.
## `LOG_COLOR`
This is mainly relevant in the context of using the dev server via the `langgraph dev` command. Set `LOG_COLOR` to `true` to enable ANSI-colored console output when using the default console renderer. Disabling color output by setting this variable to `false` produces monochrome logs. Defaults to `true`.
## `LOG_LEVEL`
Configure [log level](https://docs.python.org/3/library/logging.html#logging-levels). Defaults to `INFO`.
Set `LOG_JSON` to `true` to render all log messages as JSON objects using the configured `JSONRenderer`. This produces structured logs that can be easily parsed or ingested by log management systems. Defaults to `false`.
## `LOG_COLOR`
## `MOUNT_PREFIX`
This is mainly relevant in the context of using the dev server via the `langgraph dev` command. Set `LOG_COLOR` to `true` to enable ANSI-colored console output when using the default console renderer. Disabling color output by setting this variable to `false` produces monochrome logs. Defaults to `true`.
!!! info "Only Allowed in Self-Hosted Deployments"
The `MOUNT_PREFIX` environment variable is only allowed in Self-Hosted Deployment models, LangGraph Platform SaaS will not allow this environment variable.
Set `MOUNT_PREFIX` to serve the LangGraph Server under a specific path prefix. This is useful for deployments where the server is behind a reverse proxy or load balancer that requires a specific path prefix.
For example, if the server is to be served under `https://example.com/langgraph`, set `MOUNT_PREFIX` to `/langgraph`.
## `N_JOBS_PER_WORKER`
@@ -94,16 +114,14 @@ Database Connectivity:
- The custom Postgres instance must be accessible by the LangGraph Server. The user is responsible for ensuring connectivity.
## `LANGGRAPH_POSTGRES_POOL_MAX_SIZE`
## `REDIS_CLUSTER`
Beginning with langgraph-api version `0.2.12`, the maximum size of the Postgres connection pool can be controlled using the `LANGGRAPH_POSTGRES_POOL_MAX_SIZE` environment variable. By setting this variable, you can determine the upper bound on the number of simultaneous connections the server will establish with the Postgres database. This is particularly useful for deployments where database resources are limited (or more available) or where you need to tune connection behavior for performance or scaling reasons. If not specified, the pool size defaults to 150 connections.
!!! info "Only Allowed in Self-Hosted Deployments"
Redis Cluster mode is only available in Self-Hosted Deployment models, LangGraph Platform SaaS will provision a redis instance for you by default.
## `REDIS_URI_CUSTOM`
Set `REDIS_CLUSTER` to `True` to enable Redis Cluster mode. When enabled, the system will connect to Redis using cluster mode. This is useful when connecting to a Redis Cluster deployment.
!!! info "Only for Self-Hosted Data Plane and Self-Hosted Control Plane"
Custom Redis instances are only available for [Self-Hosted Data Plane](../../concepts/langgraph_self_hosted_data_plane.md) and [Self-Hosted Control Plane](../../concepts/langgraph_self_hosted_control_plane.md) deployments.
Specify `REDIS_URI_CUSTOM` to use a custom Redis instance. The value of `REDIS_URI_CUSTOM` must be a valid [Redis connection URI](https://redis-py.readthedocs.io/en/stable/connections.html#redis.Redis.from_url).
Defaults to `False`.
## `REDIS_KEY_PREFIX`
@@ -114,20 +132,19 @@ Specify a prefix for Redis keys. This allows multiple LangGraph Server instances
Defaults to `''`.
## `REDIS_CLUSTER`
## `REDIS_URI_CUSTOM`
!!! info "Only Allowed in Self-Hosted Deployments"
Redis Cluster mode is only available in Self-Hosted Deployment models, LangGraph Platform SaaS will provision a redis instance for you by default.
!!! info "Only for Self-Hosted Data Plane and Self-Hosted Control Plane"
Custom Redis instances are only available for [Self-Hosted Data Plane](../../concepts/langgraph_self_hosted_data_plane.md) and [Self-Hosted Control Plane](../../concepts/langgraph_self_hosted_control_plane.md) deployments.
Set`REDIS_CLUSTER` to `True` to enable Redis Cluster mode. When enabled, the system will connect to Redis using cluster mode. This is useful when connecting to a Redis Cluster deployment.
Specify`REDIS_URI_CUSTOM` to use a custom Redis instance. The value of `REDIS_URI_CUSTOM` must be a valid [Redis connection URI](https://redis-py.readthedocs.io/en/stable/connections.html#redis.Redis.from_url).
Defaults to `False`.
## `RESUMABLE_STREAM_TTL_SECONDS`
## `MOUNT_PREFIX`
Time-to-live in seconds for resumable stream data in Redis.
!!! info "Only Allowed in Self-Hosted Deployments"
The `MOUNT_PREFIX` environment variable is only allowed in Self-Hosted Deployment models, LangGraph Platform SaaS will not allow this environment variable.
When a run is created and the output is streamed, the stream can be configured to be resumable (e.g. `stream_resumable=True`). If a stream is resumable, output from the stream is temporarily stored in Redis. The TTL for this data can be configured by setting `RESUMABLE_STREAM_TTL_SECONDS`.
Set `MOUNT_PREFIX` to serve the LangGraph Server under a specific path prefix. This is useful for deployments where the server is behind a reverse proxy or load balancer that requires a specific path prefix.
See the [Python](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/#langgraph_sdk.client.RunsClient.stream) and [JS/TS](https://langchain-ai.github.io/langgraphjs/reference/classes/sdk_client.RunsClient.html#stream) SDKs for more details on how to implement resumable streams.
For example, if the server is to be served under `https://example.com/langgraph`, set `MOUNT_PREFIX` to `/langgraph`.
> **Note:** This changelog is no longer actively maintained. For the most up-to-date LangGraph Server changelog, please visit our new documentation site: [LangGraph Server Changelog](https://docs.langchain.com/langgraph-platform/langgraph-server-changelog#langgraph-server-changelog)
[LangGraph Server](../../concepts/langgraph_server.md) is an API platform for creating and managing agent-based applications. It provides built-in persistence, a task queue, and supports deploying, configuring, and running assistants (agentic workflows) at scale. This changelog documents all notable updates, features, and fixes to LangGraph Server releases.
---
## v0.2.111 (2025-07-29)
- Started the heartbeat immediately upon connection to prevent JS graph streaming errors during long startups.
## v0.2.110 (2025-07-29)
- Added interrupts as default values for all operations except streams to maintain consistent behavior.
## v0.2.109 (2025-07-28)
- Fixed an issue where missing config schema occurred when `config_type` was not set.
## v0.2.108 (2025-07-28)
- Added compatibility for langgraph v0.6, including new context API support and a migration to enhance context handling in assistant operations.
## v0.2.107 (2025-07-27)
- Implemented caching for authentication processes to improve performance.
- Merged count and select queries to improve database query efficiency.
## v0.2.106 (2025-07-27)
- Log whether run uses resumable streams.
## v0.2.105 (2025-07-27)
- Added a `/heapdump` endpoint to capture and save JS process heap data.
## v0.2.103 (2025-07-25)
- Corrected the metadata endpoint to ensure accurate data retrieval.
## v0.2.102 (2025-07-24)
- Captured interrupt events in the wait method to preserve legacy behavior and stream updates by default.
- Added support for SDK structlog in the JavaScript environment, enhancing logging capabilities.
## v0.2.101 (2025-07-24)
- Used the correct metadata endpoint for self-hosted environments, resolving an access issue.
## v0.2.99 (2025-07-22)
- Improved license validation by adding an in-memory cache and handling Redis connection errors more effectively.
- Automatically remove agents from memory that are removed from `langgraph.json` to prevent persistence issues.
- Ensured the UI namespace for generated UI is a valid JavaScript property name to prevent errors.
- Raised a 422 error for improved request validation feedback.
## v0.2.98 (2025-07-19)
- Added langgraph node context for improved log filtering and trace visibility.
## v0.2.97 (2025-07-19)
- Fixed scheduling issue with ckpt ingestion worker that occurred on isolated background loops.
- Ensured queue worker starts only after all migrations have completed.
- Added more detailed error messages for thread state issues and improved response handling when state updates fail.
- Exposed interrupt ID while retrieving thread state for enhanced API response details.
## v0.2.96 (2025-07-17)
- Added a fallback mechanism for configurable header patterns to handle exclude/include settings more effectively.
## v0.2.95 (2025-07-17)
- Avoided setting the future if it is already done to prevent redundant operations.
- Resolved compatibility errors in CI by switching from `typing.TypedDict` to `typing_extensions.TypedDict` for Python versions below 3.12.
## v0.2.94 (2025-07-16)
- Improved performance by omitting pending sends for langgraph versions 0.5 and above.
- Improved server startup logs to provide clearer warnings when the DD_API_KEY environment variable is set.
## v0.2.93 (2025-07-16)
- Removed the GIN index for run metadata to improve performance.
## v0.2.92 (2025-07-16)
- Enabled copying functionality for blobs and checkpoints, improving data management flexibility.
## v0.2.91 (2025-07-16)
- Reduced writes to the `checkpoint_blobs` table by inlining small values (null, numeric, str, etc.). This means we don't need to store extra values for channels that haven't been updated.
## v0.2.90 (2025-07-16)
- Improve checkpoint writes via node-local background queueing.
## v0.2.89 (2025-07-15)
- Decoupled checkpoint writing from thread/run state by removing foreign keys and updated logger to prevent timeout-related failures.
## v0.2.88 (2025-07-14)
- Removed the foreign key constraint for `thread` in the `run` table to simplify database schema.
## v0.2.87 (2025-07-14)
- Added more detailed logs for Redis worker signaling to improve debugging.
## v0.2.86 (2025-07-11)
- Honored tool descriptions in the `/mcp` endpoint to align with expected functionality.
## v0.2.85 (2025-07-10)
- Added support for the `on_disconnect` field to `runs/wait` and included disconnect logs for better debugging.
## v0.2.84 (2025-07-09)
- Removed unnecessary status updates to streamline thread handling and updated version to 0.2.84.
## v0.2.83 (2025-07-09)
- Reduced the default time-to-live for resumable streams to 2 minutes.
- Enhanced data submission logic to send data to both Beacon and LangSmith instance based on license configuration.
- Enabled submission of self-hosted data to a Langsmith instance when the endpoint is configured.
## v0.2.82 (2025-07-03)
- Addressed a race condition in background runs by implementing a lock using join, ensuring reliable execution across CTEs.
## v0.2.81 (2025-07-03)
- Optimized run streams by reducing initial wait time to improve responsiveness for older or non-existent runs.
## v0.2.80 (2025-07-03)
- Corrected parameter passing in the `logger.ainfo()` API call to resolve a TypeError.
## v0.2.79 (2025-07-02)
- Fixed a JsonDecodeError in checkpointing with remote graph by correcting JSON serialization to handle trailing slashes properly.
- Introduced a configuration flag to disable webhooks globally across all routes.
## v0.2.78 (2025-07-02)
- Added timeout retries to webhook calls to improve reliability.
- Added HTTP request metrics, including a request count and latency histogram, for enhanced monitoring capabilities.
## v0.2.77 (2025-07-02)
- Added HTTP metrics to improve performance monitoring.
- Changed the Redis cache delimiter to reduce conflicts with subgraph message names and updated caching behavior.
## v0.2.76 (2025-07-01)
- Updated Redis cache delimiter to prevent conflicts with subgraph messages.
## v0.2.74 (2025-06-30)
- Scheduled webhooks in an isolated loop to ensure thread-safe operations and prevent errors with PYTHONASYNCIODEBUG=1.
## v0.2.73 (2025-06-27)
- Fixed an infinite frame loop issue and removed the dict_parser due to structlog's unexpected behavior.
- Throw a 409 error on deadlock occurrence during run cancellations to handle lock conflicts gracefully.
## v0.2.72 (2025-06-27)
- Ensured compatibility with future langgraph versions.
- Implemented a 409 response status to handle deadlock issues during cancellation.
## v0.2.71 (2025-06-26)
- Improved logging for better clarity and detail regarding log types.
## v0.2.70 (2025-06-26)
- Improved error handling to better distinguish and log TimeoutErrors caused by users from internal run timeouts.
## v0.2.69 (2025-06-26)
- Added sorting and pagination to the crons API and updated schema definitions for improved accuracy.
## v0.2.66 (2025-06-26)
- Fixed a 404 error when creating multiple runs with the same thread_id using `on_not_exist="create"`.
## v0.2.65 (2025-06-25)
- Ensured that only fields from `assistant_versions` are returned when necessary.
- Ensured consistent data types for in-memory and PostgreSQL users, improving internal authentication handling.
## v0.2.64 (2025-06-24)
- Added descriptions to version entries for better clarity.
## v0.2.62 (2025-06-23)
- Improved user handling for custom authentication in the JS Studio.
- Added Prometheus-format run statistics to the metrics endpoint for better monitoring.
- Added run statistics in Prometheus format to the metrics endpoint.
## v0.2.61 (2025-06-20)
- Set a maximum idle time for Redis connections to prevent unnecessary open connections.
## v0.2.60 (2025-06-20)
- Enhanced error logging to include traceback details for dictionary operations.
- Added a `/metrics` endpoint to expose queue worker metrics for monitoring.
## v0.2.57 (2025-06-18)
- Removed CancelledError from retriable exceptions to allow local interrupts while maintaining retriability for workers.
- Introduced middleware to gracefully shut down the server after completing in-flight requests upon receiving a SIGINT.
- Reduced metadata stored in checkpoint to only include necessary information.
- Improved error handling in join runs to return error details when present.
## v0.2.56 (2025-06-17)
- Improved application stability by adding a handler for SIGTERM signals.
## v0.2.55 (2025-06-17)
- Improved the handling of cancellations in the queue entrypoint.
- Improved cancellation handling in the queue entry point.
## v0.2.54 (2025-06-16)
- Enhanced error message for LuaLock timeout during license validation.
- Fixed the $contains filter in custom auth by requiring an explicit ::text cast and updated tests accordingly.
- Ensured project and tenant IDs are formatted as UUIDs for consistency.
## v0.2.53 (2025-06-13)
- Resolved a timing issue to ensure the queue starts only after the graph is registered.
- Improved performance by setting thread and run status in a single query and enhanced error handling during checkpoint writes.
- Reduced the default background grace period to 3 minutes.
## v0.2.52 (2025-06-12)
- Now logging expected graphs when one is omitted to improve traceability.
- Implemented a time-to-live (TTL) feature for resumable streams.
- Improved query efficiency and consistency by adding a unique index and optimizing row locking.
## v0.2.51 (2025-06-12)
- Handled `CancelledError` by marking tasks as ready to retry, improving error management in worker processes.
- Added LG API version and request ID to metadata and logs for better tracking.
- Added LG API version and request ID to metadata and logs to improve traceability.
- Improved database performance by creating indexes concurrently.
- Ensured postgres write is committed only after the Redis running marker is set to prevent race conditions.
- Enhanced query efficiency and reliability by adding a unique index on thread_id/running, optimizing row locks, and ensuring deterministic run selection.
- Resolved a race condition by ensuring Postgres updates only occur after the Redis running marker is set.
## v0.2.46 (2025-06-07)
- Introduced a new connection for each operation while preserving transaction characteristics in Threads state `update()` and `bulk()` commands.
## v0.2.45 (2025-06-05)
- Enhanced streaming feature by incorporating tracing contexts.
- Removed an unnecessary query from the Crons.search function.
- Resolved connection reuse issue when scheduling next run for multiple cron jobs.
- Removed an unnecessary query in the Crons.search function to improve efficiency.
- Resolved an issue with scheduling the next cron run by improving connection reuse.
## v0.2.44 (2025-06-04)
- Enhanced the worker logic to exit the pipeline before continuing when the Redis message limit is reached.
- Introduced a ceiling for Redis message size with an option to skip messages larger than 128 MB for improved performance.
- Ensured the pipeline always closes properly to prevent resource leaks.
## v0.2.43 (2025-06-04)
- Improved performance by omitting logs in metadata calls and ensuring output schema compliance in value streaming.
- Ensured the connection is properly closed after use.
- Aligned output format to strictly adhere to the specified schema.
- Stopped sending internal logs in metadata requests to improve privacy.
## v0.2.42 (2025-06-04)
- Added timestamps to track the start and end of a request's run.
- Added tracer information to the configuration settings.
- Added support for streaming with tracing contexts.
## v0.2.41 (2025-06-03)
- Added locking mechanism to prevent errors in pipelined executions.
@@ -97,7 +97,7 @@ Parallel processing is vital for efficient multi-agent systems and complex tasks
- Implementation of map-reduce-like operations
- Efficient handling of independent subtasks
For practical implementation, see our [map-reduce tutorial](../how-tos/graph-api.ipynb#map-reduce-and-the-send-api)
For practical implementation, see our [map-reduce tutorial](../how-tos/graph-api.md#map-reduce-and-the-send-api)
### Subgraphs
@@ -107,7 +107,7 @@ For practical implementation, see our [map-reduce tutorial](../how-tos/graph-api
- Hierarchical organization of agent teams
- Controlled communication between agents and the main system
Subgraphs communicate with the parent graph through overlapping keys in the state schema. This enables flexible, modular agent design. For implementation details, refer to our [subgraph how-to guide](../how-tos/subgraph.ipynb).
Subgraphs communicate with the parent graph through overlapping keys in the state schema. This enables flexible, modular agent design. For implementation details, refer to our [subgraph how-to guide](../how-tos/subgraph.md).
* The dependencies will be loaded from a dependency file in the local directory (e.g., `package.json`).
* A single graph will be loaded from the file `./your_package/your_file.js` with the function `agent`.
* The environment variable `OPENAI_API_KEY` is set inline.
:::js
```json
{
"dependencies": [
"."
],
"graphs": {
"my_agent": "./your_package/your_file.js:agent"
},
"env": {
"OPENAI_API_KEY": "secret-key"
}
}
```
- The dependencies will be loaded from a dependency file in the local directory (e.g., `package.json`).
- A single graph will be loaded from the file `./your_package/your_file.js` with the function `agent`.
- The environment variable `OPENAI_API_KEY` is set inline.
```json
{
"dependencies": ["."],
"graphs": {
"my_agent": "./your_package/your_file.js:agent"
},
"env": {
"OPENAI_API_KEY": "secret-key"
}
}
```
:::
## Dependencies
A LangGraph application may depend on other Python packages or JavaScript libraries (depending on the programming language in which the application is written).
:::python
A LangGraph application may depend on other Python packages.
:::
:::js
A LangGraph application may depend on other TypeScript/JavaScript libraries.
:::
You will generally need to specify the following information for dependencies to be set up correctly:
:::python
1. A file in the directory that specifies the dependencies (e.g. `requirements.txt`, `pyproject.toml`, or `package.json`).
:::
:::js
1. A file in the directory that specifies the dependencies (e.g. `package.json`).
:::
2. A `dependencies` key in the [LangGraph configuration file](#configuration-file-concepts) that specifies the dependencies required to run the LangGraph application.
3. Any additional binaries or system libraries can be specified using `dockerfile_lines` key in the [LangGraph configuration file](#configuration-file-concepts).
**Assistants** allow you to manage configurations (like prompts, LLM selection, tools) separately from your graph's core logic, enabling rapid changes that don't alter the graph architecture. It is a way to create multiple specialized versions of the same graph architecture, each optimized for different use cases through configuration variations rather than structural changes.
**Assistants** allow you to manage configurations (like prompts, LLM selection, tools) separately from your graph's core logic, enabling rapid changes that don't alter the graph architecture. It is a way to create multiple specialized versions of the same graph architecture, each optimized for different use cases through context/configuration variations rather than structural changes.
For example, imagine a general-purpose writing agent built on a common graph architecture. While the structure remains the same, different writing styles—such as blog posts and tweets—require tailored configurations to optimize performance. To support these variations, you can create multiple assistants (e.g., one for blogs and another for tweets) that share the underlying graph but differ in model selection and system prompt.
@@ -14,8 +14,11 @@ The LangGraph Cloud API provides several endpoints for creating and managing ass
## Configuration
Assistants build on the LangGraph open source concept of [configuration](low_level.md#configuration).
While configuration is available in the open source LangGraph library, assistants are only present in [LangGraph Platform](langgraph_platform.md). This is due to the fact that assistants are tightly coupled to your deployed graph. Upon deployment, LangGraph Server will automatically create a default assistant for each graph using the graph's default configuration settings.
:::python
Assistants build on the LangGraph open source concepts of configuration and [runtime context](low_level.md#runtime-context).
:::
While these features are available in the open source LangGraph library, assistants are only present in [LangGraph Platform](langgraph_platform.md). This is due to the fact that assistants are tightly coupled to your deployed graph. Upon deployment, LangGraph Server will automatically create a default assistant for each graph using the graph's default context and configuration settings.
In practice, an assistant is just an _instance_ of a graph with a specific configuration. Therefore, multiple assistants can reference the same graph but can contain different configurations (e.g. prompts, models, tools). The LangGraph Server API provides several endpoints for creating and managing assistants. See the [API reference](../cloud/reference/api/api_ref.html) and [this how-to](../cloud/how-tos/configuration_cloud.md) for more details on how to create assistants.
@@ -26,6 +29,6 @@ Once you've created an assistant, subsequent edits to that assistant will create
## Execution
A **run** is an invocation of an assistant. Each run may have its own input, configuration, and metadata, which may affect execution and output of the underlying graph. A run can optionally be executed on a [thread](./persistence.md#threads).
A **run** is an invocation of an assistant. Each run may have its own input, configuration, context, and metadata, which may affect execution and output of the underlying graph. A run can optionally be executed on a [thread](./persistence.md#threads).
The LangGraph Platform API provides several endpoints for creating and managing runs. See the [API reference](../cloud/reference/api/api_ref.html#tag/thread-runs/) for more details.
@@ -16,7 +16,13 @@ While often used interchangeably, these terms represent distinct security concep
- [**Authentication**](#authentication) ("AuthN") verifies _who_ you are. This runs as middleware for every request.
- [**Authorization**](#authorization) ("AuthZ") determines _what you can do_. This validates the user's privileges and roles on a per-resource basis.
:::python
In LangGraph Platform, authentication is handled by your [`@auth.authenticate`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth.authenticate) handler, and authorization is handled by your [`@auth.on`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth.on) handlers.
:::
:::js
In LangGraph Platform, authentication is handled by your [`@auth.authenticate`](../cloud/reference/sdk/typescript_sdk_ref.md#auth.authenticate) handler, and authorization is handled by your [`@auth.on`](../cloud/reference/sdk/typescript_sdk_ref.md#auth.on) handlers.
:::
## Default Security Models
@@ -29,7 +35,8 @@ LangGraph Platform provides different security defaults:
- Can be customized with your auth handler
!!! note "Custom auth"
Custom auth **is supported** for all plans in LangGraph Platform.
Custom auth **is supported** for all plans in LangGraph Platform.
### Self-Hosted
@@ -37,34 +44,30 @@ LangGraph Platform provides different security defaults:
- Complete flexibility to implement your security model
- You control all aspects of authentication and authorization
!!! note "Custom auth"
Custom auth is supported for **Enterprise** self-hosted deployments.
Standalone Container (Lite) deployments do not support custom auth natively.
## System Architecture
A typical authentication setup involves three main components:
* A dedicated service that manages user identities and credentials
* Handles user registration, login, password resets, etc.
* Issues tokens (JWT, session tokens, etc.) after successful authentication
* Examples: Auth0, Supabase Auth, Okta, or your own auth server
- A dedicated service that manages user identities and credentials
- Handles user registration, login, password resets, etc.
- Issues tokens (JWT, session tokens, etc.) after successful authentication
- Examples: Auth0, Supabase Auth, Okta, or your own auth server
2. **LangGraph Backend** (Resource Server)
* Your LangGraph application that contains business logic and protected resources
* Validates tokens with the auth provider
* Enforces access control based on user identity and permissions
* Doesn't store user credentials directly
- Your LangGraph application that contains business logic and protected resources
- Validates tokens with the auth provider
- Enforces access control based on user identity and permissions
- Doesn't store user credentials directly
3. **Client Application** (Frontend)
* Web app, mobile app, or API client
* Collects time-sensitive user credentials and sends to auth provider
* Receives tokens from auth provider
* Includes these tokens in requests to LangGraph backend
- Web app, mobile app, or API client
- Collects time-sensitive user credentials and sends to auth provider
- Receives tokens from auth provider
- Includes these tokens in requests to LangGraph backend
Here's how these components typically interact:
@@ -84,15 +87,22 @@ sequenceDiagram
LG-->>Client: 8. Return resources
```
:::python
Your [`@auth.authenticate`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth.authenticate) handler in LangGraph handles steps 4-6, while your [`@auth.on`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth.on) handlers implement step 7.
:::
:::js
Your [`auth.authenticate`](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#authenticate) handler in LangGraph handles steps 4-6, while your [`auth.on`](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#on>) handlers implement step 7.
:::
## Authentication
:::python
Authentication in LangGraph runs as middleware on every request. Your [`@auth.authenticate`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth.authenticate) handler receives request information and should:
1. Validate the credentials
2. Return [user info](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.MinimalUserDict) containing the user's identity and user information if valid
3. Raise an [HTTP exception](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.exceptions.HTTPException) or AssertionError if invalid
3. Raise an [HTTPException](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.exceptions.HTTPException) or AssertionError if invalid
```python
from langgraph_sdk import Auth
@@ -126,9 +136,49 @@ The returned user information is available:
- To your authorization handlers via [`ctx.user`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.AuthContext)
- In your application via `config["configuration"]["langgraph_auth_user"]`
:::
:::js
Authentication in LangGraph runs as middleware on every request. Your [`authenticate`](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#authenticate>) handler receives request information and should:
1. Validate the credentials
2. Return user information containing the user's identity and user information if valid
3. Raise an [HTTPException](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#class-httpexception>) if invalid
```typescript
import { Auth, HTTPException } from "@langchain/langgraph-sdk";
export const auth = new Auth();
auth.authenticate(async (request) => {
// Validate credentials (e.g., API key, JWT token)
const apiKey = request.headers.get("x-api-key");
if (!apiKey || !isValidKey(apiKey)) {
throw new HTTPException(401, "Invalid API key");
}
// Return user info - only identity and isAuthenticated are required
// Add any additional fields you need for authorization
return {
identity: "user-123", // Required: unique user identifier
isAuthenticated: true, // Optional: assumed true by default
permissions: ["read", "write"], // Optional: for permission-based auth
// You can add more custom fields if you want to implement other auth patterns
role: "admin",
orgId: "org-456",
};
});
```
The returned user information is available:
- To your authorization handlers via the `user` property in a [callback handler](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#on)
- In your application via `config.configurable.langgraph_auth_user`
:::
??? tip "Supported Parameters"
:::python
The [`@auth.authenticate`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth.authenticate) handler can accept any of the following parameters by name:
* request (Request): The raw ASGI request object
@@ -139,19 +189,84 @@ The returned user information is available:
* authorization (str | None): The Authorization header value (e.g., "Bearer <token>")
:::
:::js
The [`authenticate`](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#authenticate) handler can accept any of the following parameters:
* request (Request): The raw request object
* body (object): The parsed request body
* path (string): The request path, e.g., "/threads/abcd-1234-abcd-1234/runs/abcd-1234-abcd-1234/stream"
* authorization (string | null): The Authorization header value (e.g., "Bearer <token>")
:::
In many of our tutorials, we will just show the "authorization" parameter to be concise, but you can opt to accept more information as needed
to implement your custom authentication scheme.
### Agent authentication
Custom authentication permits delegated access. The values you return in `@auth.authenticate` are added to the run context, giving agents user-scoped credentials lets them access resources on the user’s behalf.
Note over LangGraph: 4. Validate token (@auth.authenticate)
LangGraph -->> AuthProv: 5. Fetch user info
AuthProv -->> LangGraph: 6. Confirm validity
%% Fetch user tokens from secret store
LangGraph ->> SecretStore: 6a. Fetch user tokens
SecretStore -->> LangGraph: 6b. Return tokens
Note over LangGraph: 7. Apply access control (@auth.on.*)
%% External Service round-trip
LangGraph ->> ExternalService: 8. Call external service (with header)
Note over ExternalService: 9. External service validates header and executes action
ExternalService -->> LangGraph: 10. Service response
%% Return to caller
LangGraph -->> ClientApp: 11. Return resources
```
After authentication, the platform creates a special configuration object that is passed to your graph and all nodes via the configurable context.
This object contains information about the current user, including any custom fields you return from your [`@auth.authenticate`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth.authenticate) handler.
To enable an agent to act on behalf of the user, use [custom authentication middleware](../how-tos/auth/custom_auth.md). This will allow the agent to interact with external systems like MCP servers, external databases, and even other agents on behalf of the user.
For more information, see the [Use custom auth](../how-tos/auth/custom_auth.md#enable-agent-authentication) guide.
### Agent authentication with MCP
For information on how to authenticate an agent to an MCP server, see the [MCP conceptual guide](../concepts/mcp.md).
## Authorization
After authentication, LangGraph calls your [`@auth.on`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth.on) handlers to control access to specific resources (e.g., threads, assistants, crons). These handlers can:
After authentication, LangGraph calls your authorization handlers to control access to specific resources (e.g., threads, assistants, crons). These handlers can:
1. Add metadata to be saved during resource creation by mutating the `value["metadata"]` dictionary directly. See the [supported actions table](#supported-actions) for the list of types the value can take for each action.
2. Filter resources by metadata during search/list or read operations by returning a [filter dictionary](#filter-operations).
1. Add metadata to be saved during resource creation by mutating the metadata. See the [supported actions table](#supported-actions) for the list of types the value can take for each action.
2. Filter resources by metadata during search/list or read operations by returning a [filter](#filter-operations).
3. Raise an HTTP exception if access is denied.
If you want to just implement simple user-scoped access control, you can use a single [`@auth.on`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth.on) handler for all resources and actions. If you want to have different control depending on the resource and action, you can use [resource-specific handlers](#resource-specific-handlers). See the [Supported Resources](#supported-resources) section for a full list of the resources that support access control.
If you want to just implement simple user-scoped access control, you can use a single authorization handler for all resources and actions. If you want to have different control depending on the resource and action, you can use [resource-specific handlers](#resource-specific-handlers). See the [Supported Resources](#supported-resources) section for a full list of the resources that support access control.
:::python
Your [`@auth.on`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth.on) handlers control access by mutating the `value["metadata"]` dictionary directly and returning a [filter dictionary](#filter-operations).
```python
@auth.on
@@ -193,9 +308,42 @@ async def add_owner(
return filters
```
:::
:::js
You can granularly control access by mutating the `value.metadata` object directly and returning a [filter object](#filter-operations) when registering an [`on()`](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#on) handler.
```typescript
import { Auth, HTTPException } from "@langchain/langgraph-sdk/auth";
export const auth = new Auth()
.authenticate(async (request: Request) => ({
identity: "user-123",
permissions: [],
}))
.on("*", ({ value, user }) => {
// Create filter to restrict access to just this user's resources
const filters = { owner: user.identity };
// If the operation supports metadata, add the user identity
// as metadata to the resource.
if ("metadata" in value) {
value.metadata ??= {};
value.metadata.owner = user.identity;
}
// Return filters to restrict access
// These filters are applied to ALL operations (create, read, update, search, etc.)
// to ensure users can only access their own resources
You can register handlers for specific resources and actions by chaining the resource and action names together with the [`@auth.on`](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth.on) decorator.
You can register handlers for specific resources and actions by chaining the resource and action names together with the authorization decorator.
When a request is made, the most specific handler that matches that resource and action is called. Below is an example of how to register handlers for specific resources and actions. For the following setup:
1. Authenticated users are able to create threads, read threads, and create runs on threads
@@ -206,6 +354,8 @@ When a request is made, the most specific handler that matches that resource and
For a full list of supported resources and actions, see the [Supported Resources](#supported-resources) section below.
:::python
```python
# Generic / global handler catches calls that aren't handled by more specific handlers
import { Auth, HTTPException } from "@langchain/langgraph-sdk/auth";
export const auth = new Auth()
.authenticate(async (request: Request) => ({
identity: "user-123",
permissions: ["threads:write", "threads:read"],
}))
.on("*", ({ event, user }) => {
console.log(`Request for ${event} by ${user.identity}`);
throw new HTTPException(403, { message: "Forbidden" });
})
// Matches the "threads" resource and all actions - create, read, update, delete, search
// Since this is **more specific** than the generic `on("*")` handler, it will take precedence over the generic handler for all actions on the "threads" resource
.on("threads", ({ permissions, value, user }) => {
if (!permissions.includes("write")) {
throw new HTTPException(403, {
message: "User lacks the required permissions.",
});
}
// Not all events do include `metadata` property in `value`.
// So we need to add this type guard.
if ("metadata" in value) {
value.metadata ??= {};
value.metadata.owner = user.identity;
}
return { owner: user.identity };
})
// Thread creation. This will match only on thread create actions.
// Since this is **more specific** than both the generic `on("*")` handler and the `on("threads")` handler, it will take precedence for any "create" actions on the "threads" resources
// Setting metadata on the thread being created will ensure that the resource contains an "owner" field
// Then any time a user tries to access this thread or runs within the thread,
// we can filter by owner
value.metadata ??= {};
value.metadata.owner = user.identity;
return { owner: user.identity };
})
// Reading a thread. Since this is also more specific than the generic `on("*")` handler, and the `on("threads")` handler,
.on("threads:read", ({ user }) => {
// Since we are reading (and not creating) a thread,
// we don't need to set metadata. We just need to
// return a filter to ensure users can only see their own threads.
return { owner: user.identity };
})
// Run creation, streaming, updates, etc.
// This takes precedence over the generic `on("*")` handler and the `on("threads")` handler
.on("threads:create_run", ({ value, user }) => {
value.metadata ??= {};
value.metadata.owner = user.identity;
return { owner: user.identity };
})
// Assistant creation. This will match only on assistant create actions.
// Since this is **more specific** than both the generic `on("*")` handler and the `on("assistants")` handler, it will take precedence for any "create" actions on the "assistants" resources
// Setting metadata on the assistant being created will ensure that the resource contains an "owner" field.
// Then any time a user tries to access this assistant, we can filter by owner
value.metadata ??= {};
value.metadata.owner = user.identity;
return { owner: user.identity };
});
```
:::
Notice that we are mixing global and resource-specific handlers in the above example. Since each request is handled by the most specific handler, a request to create a `thread` would match the `on_thread_create` handler but NOT the `reject_unhandled_requests` handler. A request to `update` a thread, however would be handled by the global handler, since we don't have a more specific handler for that resource and action.
### Filter Operations {#filter-operations}
Authorization handlers can return `None`, a boolean, or a filter dictionary.
:::python
Authorization handlers can return different types of values:
- `None` and `True` mean "authorize access to all underling resources"
- `False` means "deny access to all underling resources (raises a 403 exception)"
- A metadata filter dictionary will restrict access to resources
@@ -307,6 +550,24 @@ A filter dictionary is a dictionary with keys that match the resource metadata.
A dictionary with multiple keys is treated using a logical `AND` filter. For example, `{"owner": org_id, "allowed_users": {"$contains": user_id}}` will only match resources with metadata whose "owner" is `org_id` and whose "allowed_users" list contains `user_id`.
See the reference [here](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.types.FilterType) for more information.
:::
:::js
Authorization handlers can return different types of values:
- `null` and `true` mean "authorize access to all underling resources"
- `false` means "deny access to all underling resources (raises a 403 exception)"
- A metadata filter object will restrict access to resources
A filter object is an object with keys that match the resource metadata. It supports three operators:
- The default value is a shorthand for exact match, or "$eq", below. For example, `{ owner: userId}` will include only resources with metadata containing `{ owner: userId }`
- `$eq`: Exact match (e.g., `{ owner: { $eq: userId } }`) - this is equivalent to the shorthand above, `{ owner: userId }`
- `$contains`: List membership (e.g., `{ allowedUsers: { $contains: userId} }`) The value here must be an element of the list. The metadata in the stored resource must be a list/container type.
An object with multiple keys is treated using a logical `AND` filter. For example, `{ owner: orgId, allowedUsers: { $contains: userId} }` will only match resources with metadata whose "owner" is `orgId` and whose "allowedUsers" list contains `userId`.
See the reference [here](../cloud/reference/sdk/typescript_sdk_ref.md#auth.types.FilterType) for more information.
:::
## Common Access Patterns
@@ -316,6 +577,8 @@ Here are some typical authorization patterns:
This common pattern lets you scope all threads, assistants, crons, and runs to a single user. It's useful for common single-user use cases like regular chatbot-style apps.
This pattern lets you control access based on **permissions**. It's useful if you want certain roles to have broader or more restricted access to resources.
| | `threads:create_run` | Creating or updating a run | [`RunsCreate`](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#threadscreate_run) |
| | `crons:search` | Listing cron jobs | [`CronsSearch`](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/#cronssearch) |
:::
???+ note "About Runs"
Runs are scoped to their parent thread for access control. This means permissions are typically inherited from the thread, reflecting the conversational nature of the data model. All run operations (reading, listing) except creation are controlled by the thread's handlers.
There is a specific `create_run` handler for creating new runs because it had more arguments that you can view in the handler.
:::python
There is a specific `create_run` handler for creating new runs because it had more arguments that you can view in the handler.
:::
:::js
There is a specific `threads:create_run` handler for creating new runs because it had more arguments that you can view in the handler.
[Breakpoints](../how-tos/human_in_the_loop/breakpoints.md) pause graph execution at defined points and let you step through each stage. They use LangGraph's [**persistence layer**](./persistence.md), which saves the graph state after each step.
With breakpoints, you can inspect the graph's state and node inputs at any point. Execution pauses **indefinitely** until you resume, as the checkpointer preserves the state.
<figcaption>An example graph consisting of 3 sequential steps with a breakpoint before step_3. </figcaption> </figure>
!!! tip
For information on how to use breakpoints, see [Set breakpoints](../how-tos/human_in_the_loop/breakpoints.md) and [Set breakpoints using Server API](../cloud/how-tos/human_in_the_loop_breakpoint.md).
There are two free options for deploying LangGraph applications via the LangGraph Server:
1. [Local](../tutorials/langgraph-platform/local-server.md): Deploy for local testing and development.
1. [Standalone Container (Lite)](../concepts/langgraph_standalone_container.md): A limited version of Standalone Container for deployments unlikely to see more that 1 million node executions per year and that do not need crons and other enterprise features. Standalone Container (Lite) deployment option is free with a LangSmith API key.
[Local](../tutorials/langgraph-platform/local-server.md): Deploy for local testing and development.
## Production deployment
@@ -18,9 +15,9 @@ There are 4 main options for deploying with the [LangGraph Platform](langgraph_p
1. [Cloud SaaS](#cloud-saas)
1. [Self-Hosted Data Plane<sup>(Beta)</sup>](#self-hosted-data-plane)
1. [Self-Hosted Data Plane](#self-hosted-data-plane)
1. [Self-Hosted Control Plane<sup>(Beta)</sup>](#self-hosted-control-plane)
1. [Self-Hosted Control Plane](#self-hosted-control-plane)
1. [Standalone Container](#standalone-container)
@@ -33,8 +30,7 @@ A quick comparison:
| **CI/CD** | Managed internally by platform | Managed externally by you | Managed externally by you | Managed externally by you |
| **Data/compute residency** | LangChain's cloud | Your cloud | Your cloud | Your cloud |
| **LangSmith compatibility** | Trace to LangSmith SaaS | Trace to LangSmith SaaS | Trace to Self-Hosted LangSmith | Optional tracing |
@@ -50,7 +46,7 @@ For more information, please see:
## Self-Hosted Data Plane
!!! info "Important"
The Self-Hosted Data Plane deployment option is currently in beta stage and requires an [Enterprise](../concepts/plans.md) plan.
The Self-Hosted Data Plane deployment option requires an [Enterprise](../concepts/plans.md) plan.
The [Self-Hosted Data Plane](./langgraph_self_hosted_data_plane.md) deployment option is a "hybrid" model for deployment where we manage the [control plane](./langgraph_control_plane.md) in our cloud and you manage the [data plane](./langgraph_data_plane.md) in your cloud. This option provides a way to securely manage your data plane infrastructure, while offloading control plane management to us.
@@ -66,7 +62,7 @@ For more information, please see:
## Self-Hosted Control Plane
!!! info "Important"
The Self-Hosted Control Plane deployment option is currently in beta stage and requires an [Enterprise](../concepts/plans.md) plan.
The Self-Hosted Control Plane deployment option requires an [Enterprise](../concepts/plans.md) plan.
The [Self-Hosted Control Plane](./langgraph_self_hosted_control_plane.md) deployment option is a fully self-hosted model for deployment where you manage the [control plane](./langgraph_control_plane.md) and [data plane](./langgraph_data_plane.md) in your cloud. This option gives you full control and responsibility of the control plane and data plane infrastructure.
**Durable execution** is a technique in which a process or workflow saves its progress at key points, allowing it to pause and later resume exactly where it left off. This is particularly useful in scenarios that require [human-in-the-loop](./human_in_the_loop.md), where users can inspect, validate, or modify the process before continuing, and in long-running tasks that might encounter interruptions or errors (e.g., calls to an LLM timing out). By preserving completed work, durable execution enables a process to resume without reprocessing previous steps -- even after a significant delay (e.g., a week later).
**Durable execution** is a technique in which a process or workflow saves its progress at key points, allowing it to pause and later resume exactly where it left off. This is particularly useful in scenarios that require [human-in-the-loop](./human_in_the_loop.md), where users can inspect, validate, or modify the process before continuing, and in long-running tasks that might encounter interruptions or errors (e.g., calls to an LLM timing out). By preserving completed work, durable execution enables a process to resume without reprocessing previous steps -- even after a significant delay (e.g., a week later).
LangGraph's built-in [persistence](./persistence.md) layer provides durable execution for workflows, ensuring that the state of each execution step is saved to a durable store. This capability guarantees that if a workflow is interrupted -- whether by a system failure or for [human-in-the-loop](./human_in_the_loop.md) interactions -- it can be resumed from its last recorded state.
@@ -20,7 +20,18 @@ To leverage durable execution in LangGraph, you need to:
1. Enable [persistence](./persistence.md) in your workflow by specifying a [checkpointer](./persistence.md#checkpointer-libraries) that will save workflow progress.
2. Specify a [thread identifier](./persistence.md#threads) when executing a workflow. This will track the execution history for a particular instance of the workflow.
3. Wrap any non-deterministic operations (e.g., random number generation) or operations with side effects (e.g., file writes, API calls) inside [tasks][langgraph.func.task] to ensure that when a workflow is resumed, these operations are not repeated for the particular run, and instead their results are retrieved from the persistence layer. For more information, see [Determinism and Consistent Replay](#determinism-and-consistent-replay).
:::python
3. Wrap any non-deterministic operations (e.g., random number generation) or operations with side effects (e.g., file writes, API calls) inside @[tasks][task] to ensure that when a workflow is resumed, these operations are not repeated for the particular run, and instead their results are retrieved from the persistence layer. For more information, see [Determinism and Consistent Replay](#determinism-and-consistent-replay).
:::
:::js
3. Wrap any non-deterministic operations (e.g., random number generation) or operations with side effects (e.g., file writes, API calls) inside @[tasks][task] to ensure that when a workflow is resumed, these operations are not repeated for the particular run, and instead their results are retrieved from the persistence layer. For more information, see [Determinism and Consistent Replay](#determinism-and-consistent-replay).
:::
## Determinism and Consistent Replay
@@ -30,17 +41,72 @@ As a result, when you are writing a workflow for durable execution, you must wra
To ensure that your workflow is deterministic and can be consistently replayed, follow these guidelines:
- **Avoid Repeating Work**: If a [node](./low_level.md#nodes) contains multiple operations with side effects (e.g., logging, file writes, or network calls), wrap each operation in a separate **task**. This ensures that when the workflow is resumed, the operations are not repeated, and their results are retrieved from the persistence layer.
- **Encapsulate Non-Deterministic Operations:** Wrap any code that might yield non-deterministic results (e.g., random number generation) inside **tasks** or **nodes**. This ensures that, upon resumption, the workflow follows the exact recorded sequence of steps with the same outcomes.
- **Avoid Repeating Work**: If a [node](./low_level.md#nodes) contains multiple operations with side effects (e.g., logging, file writes, or network calls), wrap each operation in a separate **task**. This ensures that when the workflow is resumed, the operations are not repeated, and their results are retrieved from the persistence layer.
- **Encapsulate Non-Deterministic Operations:** Wrap any code that might yield non-deterministic results (e.g., random number generation) inside **tasks** or **nodes**. This ensures that, upon resumption, the workflow follows the exact recorded sequence of steps with the same outcomes.
- **Use Idempotent Operations**: When possible ensure that side effects (e.g., API calls, file writes) are idempotent. This means that if an operation is retried after a failure in the workflow, it will have the same effect as the first time it was executed. This is particularly important for operations that result in data writes. In the event that a **task** starts but fails to complete successfully, the workflow's resumption will re-run the **task**, relying on recorded outcomes to maintain consistency. Use idempotency keys or verify existing results to avoid unintended duplication, ensuring a smooth and predictable workflow execution.
:::python
For some examples of pitfalls to avoid, see the [Common Pitfalls](./functional_api.md#common-pitfalls) section in the functional API, which shows
how to structure your code using **tasks** to avoid these issues. The same principles apply to the [StateGraph (Graph API)][langgraph.graph.state.StateGraph].
how to structure your code using **tasks** to avoid these issues. The same principles apply to the @[StateGraph (Graph API)][StateGraph].
:::
:::js
For some examples of pitfalls to avoid, see the [Common Pitfalls](./functional_api.md#common-pitfalls) section in the functional API, which shows
how to structure your code using **tasks** to avoid these issues. The same principles apply to the @[StateGraph (Graph API)][StateGraph].
:::
## Durability modes
LangGraph supports three durability modes that allow you to balance performance and data consistency based on your application's requirements. The durability modes, from least to most durable, are as follows:
- [`"exit"`](#exit)
- [`"async"`](#async)
- [`"sync"`](#sync)
A higher durability mode add more overhead to the workflow execution.
!!! version-added "Added in version 0.6.0"
Use the `durability` parameter instead of `checkpoint_during` (deprecated in v0.6.0) for persistence policy management:
Changes are persisted only when graph execution completes (either successfully or with an error). This provides the best performance for long-running graphs but means intermediate state is not saved, so you cannot recover from mid-execution failures or interrupt the graph execution.
### `"async"`
Changes are persisted asynchronously while the next step executes. This provides good performance and durability, but there's a small risk that checkpoints might not be written if the process crashes during execution.
### `"sync"`
Changes are persisted synchronously before the next step starts. This ensures that every checkpoint is written before continuing execution, providing high durability at the cost of some performance overhead.
You can specify the durability mode when calling any graph execution method:
:::python
```python
graph.stream(
{"input": "test"},
durability="sync"
)
```
:::
## Using tasks in nodes
If a [node](./low_level.md#nodes) contains multiple operations, you may find it easier to convert each operation into a **task** rather than refactor the operations into individual nodes.
:::python
=== "Original"
```python
@@ -48,7 +114,7 @@ If a [node](./low_level.md#nodes) contains multiple operations, you may find it
from typing_extensions import TypedDict
import uuid
from langgraph.checkpoint.memory import MemorySaver
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.graph import StateGraph, START, END
import requests
@@ -74,7 +140,7 @@ If a [node](./low_level.md#nodes) contains multiple operations, you may find it
Once you have enabled durable execution in your workflow, you can resume execution for the following scenarios:
- **Pausing and Resuming Workflows:** Use the [interrupt][langgraph.types.interrupt] function to pause a workflow at specific points and the [Command][langgraph.types.Command] primitive to resume it with updated state. See [**Human-in-the-Loop**](./human_in_the_loop.md) for more details.
:::python
- **Pausing and Resuming Workflows:** Use the @[interrupt][interrupt] function to pause a workflow at specific points and the @[Command] primitive to resume it with updated state. See [**Human-in-the-Loop**](./human_in_the_loop.md) for more details.
- **Recovering from Failures:** Automatically resume workflows from the last successful checkpoint after an exception (e.g., LLM provider outage). This involves executing the workflow with the same thread identifier by providing it with a `None` as the input value (see this [example](../how-tos/use-functional-api.md#resuming-after-an-error) with the functional API).
:::
:::js
- **Pausing and Resuming Workflows:** Use the @[interrupt][interrupt] function to pause a workflow at specific points and the @[Command] primitive to resume it with updated state. See [**Human-in-the-Loop**](./human_in_the_loop.md) for more details.
- **Recovering from Failures:** Automatically resume workflows from the last successful checkpoint after an exception (e.g., LLM provider outage). This involves executing the workflow with the same thread identifier by providing it with a `null` as the input value (see this [example](../how-tos/use-functional-api.md#resuming-after-an-error) with the functional API).
:::
## Starting Points for Resuming Workflows
* If you're using a [StateGraph (Graph API)][langgraph.graph.state.StateGraph], the starting point is the beginning of the [**node**](./low_level.md#nodes) where execution stopped.
* If you're making a subgraph call inside a node, the starting point will be the **parent** node that called the subgraph that was halted.
Inside the subgraph, the starting point will be the specific [**node**](./low_level.md#nodes) where execution stopped.
* If you're using the Functional API, the starting point is the beginning of the [**entrypoint**](./functional_api.md#entrypoint) where execution stopped.
:::python
- If you're using a @[StateGraph (Graph API)][StateGraph], the starting point is the beginning of the [**node**](./low_level.md#nodes) where execution stopped.
- If you're making a subgraph call inside a node, the starting point will be the **parent** node that called the subgraph that was halted.
Inside the subgraph, the starting point will be the specific [**node**](./low_level.md#nodes) where execution stopped.
- If you're using the Functional API, the starting point is the beginning of the [**entrypoint**](./functional_api.md#entrypoint) where execution stopped.
:::
:::js
- If you're using a [StateGraph (Graph API)](./low_level.md), the starting point is the beginning of the [**node**](./low_level.md#nodes) where execution stopped.
- If you're making a subgraph call inside a node, the starting point will be the **parent** node that called the subgraph that was halted.
Inside the subgraph, the starting point will be the specific [**node**](./low_level.md#nodes) where execution stopped.
- If you're using the Functional API, the starting point is the beginning of the [**entrypoint**](./functional_api.md#entrypoint) where execution stopped.
@@ -13,7 +13,7 @@ No. LangGraph is an orchestration framework for complex agentic systems and is m
## How is LangGraph different from other agent frameworks?
Other agentic frameworks can work for simple, generic tasks but fall short for complex tasks bespoke to a company’s needs. LangGraph provides a more expressive framework to handle companies’ unique tasks without restricting users to a single black-box cognitive architecture.
Other agentic frameworks can work for simple, generic tasks but fall short for complex tasks. LangGraph provides a more expressive framework to handle your unique tasks without restricting you to a single black-box cognitive architecture.
## Does LangGraph impact the performance of my app?
@@ -28,14 +28,14 @@ Yes. LangGraph is an MIT-licensed open-source library and is free to use.
LangGraph is a stateful, orchestration framework that brings added control to agent workflows. LangGraph Platform is a service for deploying and scaling LangGraph applications, with an opinionated API for building agent UXs, plus an integrated developer studio.
| Features | LangGraph (open source) | LangGraph Platform |
| Concurrency Control | Simple threading | Supports double-texting |
@@ -47,7 +47,7 @@ LangGraph is a stateful, orchestration framework that brings added control to ag
No. LangGraph Platform is proprietary software.
There is a free, self-hosted version of LangGraph Platform with access to basic features. The Cloud SaaS deployment option is free while in beta, but will eventually be a paid service. We will always give ample notice before charging for a service and reward our early adopters with preferential pricing. The Self-Hosted deployment options are paid services. [Contact our sales team](https://www.langchain.com/contact-sales) to learn more.
There is a free, self-hosted version of LangGraph Platform with access to basic features. The Cloud SaaS deployment option and the Self-Hosted deployment options are paid services. [Contact our sales team](https://www.langchain.com/contact-sales) to learn more.
For more information, see our [LangGraph Platform pricing page](https://www.langchain.com/pricing-langgraph-platform).
@@ -67,4 +67,4 @@ If you set an environment variable of `LANGSMITH_TRACING=false`, then no traces
## What does "nodes executed" mean for LangGraph Platform usage?
**Nodes Executed** is the aggregate number of nodes in a LangGraph application that are called and completed successfully during an invocation of the application. If a node in the graph is not called during execution or ends in an error state, these nodes will not be counted. If a node is called and completes successfully multiple times, each occurrence will be counted.
**Nodes Executed** is the aggregate number of nodes in a LangGraph application that are called and completed successfully during an invocation of the application. If a node in the graph is not called during execution or ends in an error state, these nodes will not be counted. If a node is called and completes successfully multiple times, each occurrence will be counted.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.