Commit Graph
3002 Commits
Author SHA1 Message Date
Caspar BroekhuizenandGitHub 11834512db test(cli): add tests for util.py (#6172)
### Description

Added unit tests for util.py.

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

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

---------

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

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

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

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

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

---------

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

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

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

**Issue**: #6050 

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

---------

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

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

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

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

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

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

------
https://chatgpt.com/codex/tasks/task_e_68c9727ca9f8832d9f207323c5e02a72
2025-09-16 16:25:47 +01:00
Caspar BroekhuizenandGitHub 9467a0e2bb revert(langgraph): restore logic to surface interrupts for stream_mod… (#6141)
### Description

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

Resolves #5409 

### Test

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

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

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

---------

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

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

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

  **Dependencies:**
  None
2025-09-14 23:34:34 +00:00
William FHandGitHub a3ee814539 chore(langgraph): Log when no values event is emitted from RemoteGraph (#6140) 2025-09-12 14:05:07 -07:00
William FHandGitHub b65140a892 chore(cli): Add config schema (#6142)
So you can IDE LSP support / autocompletion
2025-09-12 12:16:07 -07:00
f087567853 fix(cli): handle Docker SemVer build metadata in version parsing #5965 (#6024)
Description:
Corrects _parse_version to support Docker versions with SemVer build
metadata (e.g., 28.1.1+1), resolving #5965. Adds comprehensive unit
tests for version parsing, including normal, v-prefixed, prerelease,
build metadata, combined prerelease/build metadata, and edge cases with
missing components.

Issue:
Closes #5965

Dependencies:
None

---------

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

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

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

See this example:
<details>

<summary>code</summary>

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

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

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

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

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

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

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

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

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

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

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

</details>

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

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

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

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

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

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

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

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

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

### Issue

Closes #4394

---------

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

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

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

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

Long term we probably want a more robust approach to configurable
management in terms of required / not required attributes.
2025-09-10 12:19:33 +00:00
20581e61c0 fix(checkpoint-postgres): export PoolConfig from package init (#5934)
### Description
Export PoolConfig from langgraph.store.postgres.__init__ so the
documented import from langgraph.store.postgres import
AsyncPostgresStore, PoolConfig works as shown in the AsyncPostgresStore
examples. This resolves a docs vs. code inconsistency without changing
behavior.

### Issue
N/A

### Dependencies:
None

---------

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

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

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

### Tests & Docs

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

### Issue
Fixes #5946
2025-09-09 17:52:11 +00:00
Mohammad MohtashimandGitHub faacbc1570 docs(prebuilt): remaining_steps explanation added in create_react_agent (#5847)
- **Description:** A better explanation of `remaining_steps` to clarify
what it does.
- **Issue:** #5548
2025-09-09 15:07:07 +00:00
Sydney RunkleandGitHub e6a9e1d1c1 chore: update examples with context API (#5865) 2025-09-09 10:31:40 -04:00
Sydney RunkleandGitHub cd33de2ad1 chore: minor CI/link fixes (#6116) 2025-09-09 14:22:19 +00:00
zzxxj216andGitHub 1539a55d2c docs(langgraph): correct typo "runtie" to "runtime" in StateGraph (#6060)
**Description:** Fix a typo where "runtie" was incorrectly used instead
of "runtime" in line 158 of the StateGraph class in state.py. This
resolves the example error caused by the misspelled variable name.

**Dependencies:** None
2025-09-08 20:54:35 +00:00
Sydney RunkleandGitHub 6fc5b3aeda release(langgraph): 0.6.7 (#6092) 2025-09-07 13:49:43 +00:00
Harrison ChaseandGitHub b543752878 chore: update emphemeral local (#6091)
basically - for conditional edges, we use this to merge the updates from
state with the state object (before the actual update really occurs in
the tick.after)

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

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

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

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

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

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

---------

Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com>
2025-09-04 12:29:11 -07:00
William FHandGitHub 25ba4c3bda feat(sdk-py): Specify ttl on thread creation and update (#6075) 2025-09-03 18:48:57 -07:00
William FHandGitHub 6f4c5fefee feat(sdk-py): Support ids filtering in threads search (#6067) 2025-09-02 17:49:11 -07:00
Isaac FranciscoandGitHub 22942d4eec release(sdk-py): 0.2.4 (#6038) 2025-08-28 23:34:33 +00:00
Isaac FranciscoandGitHub 1756ce1dd2 feat(sdk-py): add endpoint for thread streaming (#6009)
SDK support for:
https://github.com/langchain-ai/langgraph-api/pull/1217/
2025-08-28 16:12:04 +00:00
Isaac FranciscoandGitHub 0b4638269b feat(sdk-py): add durability flag (#5963) 2025-08-27 19:21:25 +00:00
Isaac FranciscoandGitHub 1ebdb1ba31 chore: Update schema for new config allowed in LGP (#5875) 2025-08-27 11:20:06 -07:00
William FHandGitHub ddf4e62bde release(cli): 0.4.0 (#6014)
Relax upper-bound to permit server versions 0.4.*
2025-08-26 12:59:12 +00:00
William FHandGitHub d73902ae76 feat(sdk-py): Count endpoints (#5986) 2025-08-21 18:15:52 +00:00
William FHandGitHub 501ba8be34 release(cli): Bump max bound of langgraph-api (#5978) 2025-08-21 00:59:27 +00:00
William FHandGitHub 998e194e82 release(cli): Support bookworm, trixie, etc. (#5975)
Also add support for pinning to a semantic version.
2025-08-20 15:40:04 +00:00
William FHandGitHub a692e24a58 fix(langgraph): Remote Baggage (#5964)
Fix baggage propagation for opt-in distributed tracing when no
additional headers are provided.
2025-08-20 01:47:12 +00:00
William FHandGitHub c0b29a6df5 chore(langgraph): Add passthrough params/headers to invoke/stream/etc. (#5940) 2025-08-18 19:38:08 +00:00
William FHandGitHub 3488eb2a2c chore(sdk-py): Update types (#5939) 2025-08-18 18:29:07 +00:00
wakita181009andGitHub 875f20ba9f feat(sdk-py): define aclose method to LangGraphClient (#5931)
This PR adds an aclose method to the LangGraphClient.

When using the client in a FastAPI application, it's common to share a
single instance across the application's lifespan. The absence of an
aclose method makes it difficult to gracefully close the underlying HTTP
session on application shutdown. This change enables proper resource
management by allowing the client to be closed cleanly.
2025-08-18 11:22:02 -07:00
William FHandGitHub 723d4641b0 chore(sdk-py): Update params type in SDK (#5937) 2025-08-18 17:53:20 +00:00
William FHandGitHub 9918488169 feat(sdk-py): client qparams (#5918)
And add linting & dyanmic version string
2025-08-18 10:05:24 -07:00