mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-10-14 20:25:23 +02:00
c4a5cb4d2f6259600a814d269414dbef896e4154
3802
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c4a5cb4d2f |
Reject --image-pull-secret when a --name lookup finds an existing deployment
--image-pull-secret was only guarded against an existing --deployment-id. If --name (or the default name) resolved to an existing deployment instead, CustomerRegistrySource._update silently dropped the secrets: the image pull secret the user intended never reached the control plane and the revision could fail with ImagePullBackOff with no warning. |
||
|
|
a751d09a52 |
feat(cli): add --image-pull-secret for deploying through a private registry
Self-hosted and listener-based deployments created with --push-to or --image-uri had no way to tell the control plane which Kubernetes secret to use for pulling the image, so they couldn't deploy at all when the registry requires authentication. The control plane's resource_spec already supports image_pull_secrets; the CLI just never exposed a way to set it. Add a repeatable --image-pull-secret flag, following the same validation pattern as --listener-id/--k8s-namespace (only valid when creating a deployment with --push-to or --image-uri, not on an existing --deployment-id). |
||
|
|
a6731f4367 |
fix(langgraph): keep a DeltaChannel's value when its field changes to a plain reducer (#9302)
Changing a field from a `DeltaChannel` to a plain reducer, for example to `Annotated[list, add_messages]`, made threads written under the `DeltaChannel` read that field as empty. The next run saved its writes over the empty value, so continuing an old thread replaced its history. The writes were still stored: the read only rebuilt fields whose current annotation is a `DeltaChannel`. - A `BinaryOperatorAggregate` stores its value at every version, so one with a version and nothing stored was written as a `DeltaChannel`. It's now rebuilt from the same history walk, one `update` per write, since a single call would reject a second `Overwrite` and drop the writes after one. - `BinaryOperatorAggregate.from_checkpoint` unwraps a stored `_DeltaSnapshot`. - The next run saves the full value, so later reads are plain reads, and switching back to a `DeltaChannel` keeps everything. Threads written under a plain reducer never walk. A rebuilt read costs the walk plus one reducer call per write since the last snapshot: with `add_messages` on `InMemorySaver`, 25 ms at 2,048 messages with a snapshot every 50 writes, and 0.3 s at 1,998 or 0.9 s at 4,998 messages with the default 1000. After one run, reads take 6 to 16 ms. `test_delta_channel_to_plain.py` covers every saver; all but the plain-thread test fail on main. JS: langchain-ai/langgraphjs#3017 |
||
|
|
8a77332d0d |
release(cli): 0.4.34 (#9300)
Bumping the CLI to 0.4.34 to cut a release including #9243 (--json on deploy listeners list). |
||
|
|
a1ce197234 |
feat(cli): add --json to deploy listeners list (#9243)
## Summary `deploy listeners list` only prints a human-readable table, which a deploy automation pipeline can't reliably parse to extract a listener's id for `--listener-id`. Adds `--json`, which prints the listeners as a JSON array instead of the table. An empty workspace prints `[]` rather than the "No listeners found" sentence, so callers never need to special-case the no-results path when scripting against it. ## Test plan - [x] `make format && make lint` clean in `libs/cli` - [x] `test_deploy_listeners_list_command_json` and `test_deploy_listeners_list_command_json_no_results` in `test_cli.py`, mirroring the existing table-output test pair - [x] Full `libs/cli` suite: 529 passed, no regressions |
||
|
|
afbe7e48b1 |
release(checkpoint-postgres): 3.1.3 (#9287)
Version bump only. No library code changes in this PR. Unreleased since `checkpointpostgres==3.1.2`: - #8617 - widen `Store` `put` value type to `Mapping[str, Any]` - #8556 - derive the delta walk cursor once the target loads - #8544 - order delta channel replay by task path - #9217 - validate namespace labels before store dispatch - #9248 - start the delta walk at the target - #9262 - treat an empty `checkpoint_id` as the latest in delta history Follows `checkpoint==4.3.0`, which is already live on PyPI. #8544 raised the floor to `langgraph-checkpoint>=4.3.0`, so this release needs it. |
||
|
|
1074714c26 |
release(checkpoint-sqlite): 3.1.2 (#9288)
Version bump only. No library code changes in this PR. Unreleased since `checkpointsqlite==3.1.1`: - #8617 - widen `Store` `put` value type to `Mapping[str, Any]` - #8557 - walk delta ancestors by parent pointer - #8544 - order delta channel replay by task path - #9217 - validate namespace labels before store dispatch - #9262 - treat an empty `checkpoint_id` as the latest in delta history Follows `checkpoint==4.3.0`, which is already live on PyPI. #8544 raised the floor to `langgraph-checkpoint>=4.3.0`, so this release needs it. |
||
|
|
740461ed50 |
release(sdk-py): 0.4.7 (#9289)
Bumps the Python SDK version from 0.4.6 to 0.4.7. A thread stream's run now ends only on the root graph's `completed` or `failed` event, not a subgraph's, so `thread.output` no longer reads the state too early and a run that fails after a subgraph finishes is reported as failed (#9228). |
||
|
|
08a345637f |
release(langgraph): 1.2.15 (#9283)
Bumps langgraph from 1.2.14 to 1.2.15. It now requires langgraph-checkpoint 4.3.0 or later (#8544). Also includes: - Order delta channel replay by task path (#8544) - Replay a resumed exit-mode run's delta writes in live order (#9114) - Give each `bulk_update_state` update its own task id (#9128) - Stop `astream_events` dropping control/interrupts on v1/v2 (#9219) - Never store exit-mode delta writes under the null task id (#9229) - Mark a resume value that fails an interrupt's `response_schema`, so `ToolNode` can stop swallowing it once langgraph-prebuilt is released (#9232) - Don't save a checkpoint past a failed DeltaChannel write (#9235) - Keep a fork's DeltaChannel snapshot from starting nodes that never ran (#9264) - Snapshot a DeltaChannel that an `update_state` Overwrite resets (#9263) - Read a run's DeltaChannel input back only on its own checkpoints (#9260) - Store an `update_state` input's writes on the checkpoint it updates (#9258) - Keep an exit run from a checkpoint the thread moved past out of its newer branch (#9269) - Stop at an `interrupt_before` breakpoint when a drain is requested before it (#9281) - Save a cached node's writes like a node that ran (#9259) - Give every message written to a messages DeltaChannel an id (#9275) |
||
|
|
b7d053b256 |
fix(langgraph): give every message written to a messages DeltaChannel an id (#9275)
A DeltaChannel replays its saved writes on every read, and
`_messages_delta_reducer` doesn't fill in missing ids, so the loop gives
messages their ids before saving them (`ensure_message_ids`). That
missed several cases:
- Strings and `(role, content)` tuples, alone or in a list (`[("user",
"hi")]`), and messages inside an `Overwrite` were saved with no id, so
nothing could target them by id, for example `RemoveMessage`. A regular
messages channel gives them ids.
- A raw `Pregel` graph's input to a DeltaChannel got its ids after it
was applied, and none with exit durability or on a new thread; a dict
given as input read back with an id its nodes never saw. A
`Command(update=...)` sent to an older checkpoint got none either.
Now, in a DeltaChannel whose reducer is `_messages_delta_reducer`, every
message-like the reducer accepts becomes a message with an id before the
writes are saved or applied: in `put_writes`, before input is applied,
for a forked `Command`, and in `update_state`. Anything that can't
become a message is left as it is, so it fails where it always has.
Other DeltaChannels keep the rule they had (message objects, and message
dicts in a list, get ids), since they may hold other data and
deepagents' messages channel, which uses its own copy of the reducer,
relies on it; the dicts in an `Overwrite` there are left as they are.
Lists and dicts the caller passed in are never changed: a write that
changes is replaced. So the id step can recognize the reducer without an
import cycle, `_messages_delta_reducer` now lives in
`langgraph.pregel._messages`; `langgraph.graph.message` re-exports it.
Visible changes: in a messages DeltaChannel, a node's update streams as
messages with ids, and a string is stored as a message (about 170 bytes
more each).
JS twin: langchain-ai/langgraphjs#2992. Thanks to @HarshShroff for
testing every `Overwrite` form and for the tuple fix.
## Tests
`test_delta_channel_id_stability.py` and
`test_delta_channel_update_state.py`: a write of every shape the reducer
accepts gets an id that every read keeps, as input, from a node and
through `update_state` (sync, async and as input); a list written twice
adds its messages twice and stays as it was; a forked `Command` gets an
id; a message dict the reducer rejects in a list still fails the run
before it's saved; a raw `Pregel` input gets an id on a new thread with
every durability, and its nodes see the ids that are saved; another
DeltaChannel keeps the dicts in an `Overwrite`. 36 of the 87 tests in
these files fail on main. The langgraph and prebuilt suites pass, and
lint is clean.
---------
Co-authored-by: Harsh Shroff <29751900+HarshShroff@users.noreply.github.com>
|
||
|
|
395c145c04 |
fix(langgraph): save a cached node's writes like a node that ran (#9259)
A node served from the node cache had its writes applied but never saved: the loop only streamed them. Plain channels didn't notice, since the next checkpoint stores their value, but a `DeltaChannel` is rebuilt from the saved writes, so its saved state lost the cached node's write for good, under every durability. With `a -> b -> c` and `b` cached, a second thread read back `log` as `a, c` next to `plain` as `a, b, c`. The loop now saves a cache hit with `put_writes`, like a node that ran, in all six places it matches cached writes. A new `cached` flag keeps the hit streamed as cached and stops `put_writes` from writing it back to the cache, which would also restart its TTL. A hit now costs the saver write the node makes when it runs, and a cached `@task` call's result is saved the same way. The sync loop also stops caching a node that failed or was interrupted, as the async loop already did: a cached error made the next run with the same input skip the node without raising. Found in review of langchain-ai/langgraphjs#2969. JS twin: langchain-ai/langgraphjs#2980 ## Tests - `test_delta_channel_node_cache.py`: `b` runs on the first thread and is a cache hit on the second, under every durability, with `invoke` and `ainvoke`. Every checkpoint of the second thread reads the same in the DeltaChannel and a plain channel, and the cache is written once. All 6 cases fail on main; without the `cached` check in `put_writes`, they fail on the cache count. - `test_a_node_that_fails_is_not_cached`, with `invoke` and `ainvoke`: a cached node that raises raises again on the next thread. The sync case fails on main. - The two tests that spy on `PregelLoop.put_writes` pass the new keyword through. - `make format`, `make lint_package`, `make lint_tests`, and the `langgraph`, `prebuilt` and `cli` suites pass (without Redis). |
||
|
|
10f1fabb3b |
fix(langgraph): stop at an interrupt_before breakpoint when a drain is requested before it (#9281)
When a drain is requested during the step right before an interrupt_before breakpoint, the run stops with GraphDrained and the breakpoint is lost: resuming the run skips it unintentionally. The fix moves the drain check in tick() after the breakpoint check, so breakpoints win over draining. JS twin: langchain-ai/langgraphjs#3009 |
||
|
|
799c2f04fd |
fix(langgraph): keep an exit run from a checkpoint the thread moved past out of its newer branch (#9269)
An exit-durability run that starts from a checkpoint the thread has
moved past, addressed by `checkpoint_id`, stores its DeltaChannel writes
on that checkpoint. The branch that already grew from it reads the
writes stored there, so its checkpoints picked up this run's writes too:
```python
graph.invoke({"log": ["in1"]}, config) # nodes a and b add "a1", "b1"
turn_1 = graph.get_state(config).config
graph.invoke({"log": ["in2"]}, config)
turn_2 = graph.get_state(config).config
graph.invoke({"log": ["in3"]}, turn_1, durability="exit")
graph.get_state(turn_2).values["log"]
# ["in1", "a1", "b1", "in3", "a3", "b3", "in2", "a2", "b2"], was ["in1", "a1", "b1", "in2", "a2", "b2"]
```
Sync and async durability store each step's writes on the run's own
checkpoints, so they weren't affected. The run now snapshots the
DeltaChannels it wrote instead, as a run's input already does on a
checkpoint a `checkpoint_id` addressed (#9260). That costs one snapshot
of each channel the run wrote, even when the addressed checkpoint is the
latest one. Threads that already hit this keep the wrong values on the
existing branch.
Found by @hntrl in review of langchain-ai/langgraphjs#2974
([repro](https://gist.github.com/hntrl/2185e489abe22147b3f6f77010c18264)).
JS twin: langchain-ai/langgraphjs#2989
## Tests
`test_delta_channel_exit_mode.py`: one and two exit runs from the end of
turn 1, after turn 2, leave every checkpoint's DeltaChannel equal to a
plain reducer channel. Both fail on main on every saver in the fixture.
The `langgraph` suite passes (without Redis), and lint is clean.
|
||
|
|
b4991f1ba3 |
fix(langgraph): store an update_state input's writes on the checkpoint it updates (#9258)
`update_state(..., as_node="__input__")` stored its writes on the checkpoint it saved. A DeltaChannel reads the writes stored on a checkpoint's ancestors, not its own, so that checkpoint read back without the input unless the channel snapshotted there, and once a later checkpoint snapshotted, the input was gone for good. Only a raw `Pregel` graph whose input channel is a DeltaChannel hits it, since a `StateGraph`'s input goes to its start channel. The input's writes now go on the checkpoint the update builds on, as a node update's do. An update on a checkpoint the thread has moved past stores nothing there and snapshots the DeltaChannels it writes on its own checkpoint instead, the rule a node update already follows (#9165). Both kinds of update now go through one helper, which also gives a message an id before saving it, as the loop's `put_writes` does with `ensure_message_ids`. Before, a message saved through `update_state` without an id read back with id `None`, on the node path too, while the same message from a node got one. JS twin: langchain-ai/langgraphjs#2973, where review found it. ## Tests `test_delta_channel_update_state.py`, sync and async: an update as input reads back on its checkpoint and after the next run, with `snapshot_frequency` 1 and 2, and an update as input to an older checkpoint stays out of its other branch. The frequency 2 and older-checkpoint cases fail on main. Five more check that a message saved through `update_state` gets an id every read keeps, on the node path (latest and older checkpoint) and the input path, sync and async; they fail on main. The langgraph suite passes, and `lint_package` and `lint_tests` are clean. |
||
|
|
6aa0afba68 |
fix(checkpoint): default InMemorySaver delta history to the latest checkpoint (#9257)
`InMemorySaver.get_delta_channel_history` looked its target up by
`config["configurable"].get("checkpoint_id", "")`, so a config without a
`checkpoint_id` matched no checkpoint, and every channel came back with
no seed and no writes, which a `DeltaChannel` reads as empty. The base
implementation, `PostgresSaver` and `SqliteSaver` read from the thread's
latest checkpoint instead, as `get_tuple` does.
A missing id now resolves to the namespace's newest checkpoint id, with
the same `max` that `InMemorySaver.get_tuple` uses. Graphs always pass a
checkpoint id here, so only direct callers of the saver API were
affected, and a call with an id does the same work as before.
Thanks @Hotragn, who pinned this down on #8242, where @longquanzheng's
branch had already fixed it.
JS twin: langchain-ai/langgraphjs#2979
## Tests
- `test_get_channel_writes_without_checkpoint_id_reads_the_latest` fails
on main (`{'messages': {'writes': []}}`).
- The `checkpoint`, `checkpoint-conformance`, `checkpoint-sqlite`,
`checkpoint-postgres` (Postgres 16), `prebuilt` and `langgraph` suites
pass, the last two without their Redis cases. The DeltaChannel
conformance suite also passes against `InMemorySaver`; CI skips that run
in `libs/checkpoint`, where the conformance package isn't installed, so
the new test lives in `test_memory.py`.
|
||
|
|
12aeb0fddb |
fix(langgraph): read a run's DeltaChannel input back only on its own checkpoints (#9260)
A raw `Pregel` graph whose input channel is a DeltaChannel saved a run's
input to it as a `NULL_TASK_ID` write on the checkpoint the run started
from, under `"sync"` and `"async"` durability. Readers apply a
checkpoint's `NULL_TASK_ID` writes as its own state, so:
- on a new thread that checkpoint is never saved, and the first run's
input was lost for good: after `{"log": [0], "plain": [0], ...}`, `log`
read `[2]` next to `plain` `[0, 2]`;
- the last checkpoint of a run read the next run's input;
- a run with input from an older checkpoint (`checkpoint_id`) leaked its
input into the branch that already grew from it, and read that branch's
input when it had one.
The input's writes now go on the checkpoint the run starts from under a
task id of their own, `uuid5(checkpoint_id, INPUT)`, the one
`update_state` uses for an input update. On a new thread, or a
checkpoint a `checkpoint_id` addressed, which may already have children
that would read them, nothing is stored there and the input checkpoint
snapshots the channel instead. A normal run stores the same write as
before, and `durability="exit"`, which already kept the input right, is
unchanged. Threads saved before this keep the input writes already
stored on their checkpoints.
A `StateGraph` routes its input through its start channel, so only raw
`Pregel` graphs hit this.
JS twin: langchain-ai/langgraphjs#2981
## Tests
`test_delta_channel_run_input.py`, under every durability, with `invoke`
and `ainvoke`: two runs on a new thread, and a run with input from an
older checkpoint whose other branch had DeltaChannel input or none.
Every checkpoint reads the same in the DeltaChannel and a plain channel.
The 12 sync and async cases fail on main, and dropping the task id, the
new-thread snapshot or the addressed-checkpoint snapshot each fails its
own cases. The `langgraph` and `prebuilt` suites pass (without Redis),
and `lint_package` and `lint_tests` are clean.
|
||
|
|
d05236f805 |
fix(langgraph): snapshot a DeltaChannel that an update_state Overwrite resets (#9263)
A node that writes an `Overwrite` to a DeltaChannel makes the loop snapshot the channel on the checkpoint that superstep saves, so no read replays across the reset. The same write through `update_state`, as a node or as input, didn't snapshot: the value read back right, but reads of the update's checkpoint and the ones after it walked back past the reset to the last snapshot. `update_state` now snapshots a DeltaChannel an `Overwrite` resets, as the loop does. Raised in review of langchain-ai/langgraphjs#2973. JS twin: langchain-ai/langgraphjs#2982 ## Tests `test_delta_channel_update_overwrite.py`, sync and async: an `Overwrite` through `update_state` as a node, and as input to a raw `Pregel` graph, snapshots the channel on the checkpoint the update saves, and the value reads back as the overwrite. All four fail on main. The `langgraph` suite passes (without Redis), and `lint_package` and `lint_tests` are clean. |
||
|
|
9d92f33cca |
fix(langgraph): keep a fork's DeltaChannel snapshot from starting nodes that never ran (#9264)
A fork from a checkpoint with pending writes to a DeltaChannel snapshots
the channel on the fork's first checkpoint, so the fork doesn't replay
the other branch's writes. If the channel had never been written there,
the snapshot also gives it its first version, and `_mark_bumps_seen`
only marked the bump seen for nodes that already have a `versions_seen`
entry. A node subscribed to the channel that never ran has none, so the
bump started it, and it read the empty value before the node that writes
the channel had run:
```python
graph.invoke("go", config) # writer writes [1] to d, reader reads [1]
fork = graph.update_state(first_checkpoint, {"a": "go"}, as_node="__input__")
graph.get_state(fork).next # ("writer", "reader"): resuming runs reader on [] first
```
A replay from that checkpoint saves the same kind of fork from the loop.
A channel bumped from no version was never written, so
`create_checkpoint` now also marks the bump seen for the nodes the
channel triggers, from the graph's `trigger_to_nodes`, at every call
that can bump. Only raw `Pregel` graphs hit this: `StateGraph` nodes
trigger on their `branch:to:*` channels, not on state keys. An
`as_node="__copy__"` fork still starts such a node, with a plain list
channel as well, so that case isn't DeltaChannel-specific and isn't
changed here.
Raised in review of langchain-ai/langgraphjs#2974. JS twin:
langchain-ai/langgraphjs#2983
## Tests
`test_delta_channel_seal_subscribers.py`: an update as input (sync and
async) and a replay from the checkpoint before a DeltaChannel's first
write leave only the writer next, and the reader then reads the written
value once. All three fail on main. The `langgraph` suite passes
(without Redis), and `lint_package` and `lint_tests` are clean.
|
||
|
|
26356227c4 |
test(checkpoint): run the delta conformance suite against InMemorySaver in CI (#9261)
The conformance self-test in `libs/checkpoint-conformance` ran every capability against `InMemorySaver` but asserted only the base ones. `libs/checkpoint/tests/test_conformance_delta.py`, which ran the delta conformance tests against it, always skips in CI: `libs/checkpoint` can't depend on the conformance package, which depends on it. So no CI job checked `InMemorySaver.get_delta_channel_history` against the delta conformance tests. The self-test now asserts every capability `InMemorySaver` implements, and the skipped copy is gone. ## Tests - With `InMemorySaver.get_delta_channel_history` broken to return no history, the self-test now fails on 7 of the 10 delta conformance tests; on main it still passes. - `make format`, `make lint` and `make test` pass in `libs/checkpoint-conformance`. |
||
|
|
a5dbacae0d |
fix(checkpoint-postgres,checkpoint-sqlite): treat an empty checkpoint_id as the latest in delta history (#9262)
`PostgresSaver` and `SqliteSaver`, sync and async, read a DeltaChannel's history from the latest checkpoint only when the config's `checkpoint_id` was missing or `None`. An empty one was looked up as an id, matched nothing, and came back with no seed and no writes, while their own `get_tuple` treats an empty id as the latest checkpoint, as the default implementation does. They now check for a missing or empty id the way `get_tuple` does. The in-memory saver gets the same in #9257. Graphs always pass the id of a saved checkpoint, so only direct callers of the saver API hit this. ## Tests - `test_{sync,async}_empty_checkpoint_id_reads_from_the_latest_checkpoint` in `checkpoint-postgres/tests/test_delta_pagination.py` and `checkpoint-sqlite/tests/test_delta_parent_walk.py`: all four fail on main. - The `checkpoint-postgres` (Postgres 16) and `checkpoint-sqlite` suites pass, and `lint_package` and `lint_tests` are clean in both. |
||
|
|
cba111d8d6 |
fix(langgraph): don't save a checkpoint past a failed DeltaChannel write (#9235)
A DeltaChannel is rebuilt from its writes along the parent chain, so a checkpoint saved without one of them reads back short for good. If saving a DeltaChannel write failed (a database blip, say), the next checkpoints were saved anyway and the channel lost that write, while plain channels kept it. Three things let that happen: - the sync loop waited for the delta writes before saving a checkpoint, but never checked that they succeeded; - both loops saved a checkpoint even when the previous save had failed, so it pointed at a parent that was never saved; - each save took the pending write list only when it started in the background, and saves can start out of order, so a save could take a later checkpoint's writes and not wait for its own. Waiting on writes queued behind it, a save could also hang a sync run with `durability="async"` (the default) once every worker was such a save: on a 15-core machine a loop of 100 fast steps hung every time with default settings, and with `max_concurrency=1` three steps are enough. Now `_put_checkpoint` hands each save the writes submitted before it, and a save fails if one of them or the previous save failed. The run raises the write's error as before, the thread stays at its last checkpoint that has all its writes, and running it again reruns the task. For graphs without a DeltaChannel, a failed save now also stops the later saves of that run, as JS already does, instead of saving checkpoints whose parent is missing. Thanks @shivangsharma01 for reproducing this in #8234, and @iroiro147, whose #8299 had the first two changes before the issue-assignment check closed it. Thanks also to @HarshShroff for the failed-save test case. JS twin: langchain-ai/langgraphjs#2969 ## Tests `test_delta_channel_write_failures.py`: - a saver fails one delta write once; on every durability, with `invoke` and `ainvoke`, every saved checkpoint matches a plain channel and a retry gets the write back. The `invoke` cases and `ainvoke` with `durability="async"` fail on main. - a saver fails the save of the checkpoint after `a` once; with `invoke` and `ainvoke`, every saved checkpoint matches a plain channel and a retry finishes the run. The `durability="async"` cases fail on main, which saves the later checkpoints on top of the missing one. - a delta graph run with `max_concurrency=1` finishes. It hangs on main. Reverting any one of the three changes fails at least one of these. `make format`, `make lint` and the langgraph suite pass. A 100-step benchmark (delta and plain channels, every durability, with and without 1 ms of saver latency) makes the same saver calls and runs in the same time as main, except for the case that hangs on main. --------- Co-authored-by: iroiro147 <265728356+iroiro147@users.noreply.github.com> |
||
|
|
93a5a28008 |
perf(checkpoint-postgres): start the delta walk at the target (#9248)
Reading a DeltaChannel at an older checkpoint (the state at a past checkpoint, each entry of `get_state_history`, a fork or replay from one) walked `checkpoints` down from the newest row, so every newer row was read before the target's chain. A checkpoint's ancestors have smaller ids, the order `get_tuple` already relies on to find the latest checkpoint, so the walk now starts at the target: the first page is `checkpoint_id <= target`, later pages stay `< cursor`. The cursor is never NULL anymore, so the `(cursor IS NULL OR checkpoint_id < cursor)` predicate goes too. Once Postgres caches a generic plan for the prepared statement (`from_conn_string` sets `prepare_threshold=0`), that predicate is a filter rather than an index condition, and each later page re-read every newer row. `get_delta_channel_history` on a 6,000-checkpoint thread with a snapshot every 200 checkpoints, median of three runs of 60 reads each, same results before and after: | target | main | this PR | |---|---|---| | newest | 3.1 ms | 2.7 ms | | 1,000 back | 4.5 ms | 2.9 ms | | 3,000 back | 8.9 ms | 2.8 ms | | 5,000 back | 15.7 ms | 2.8 ms | The target is now always the first row read, so the pagination tests from #8556 can no longer leave it off the first page; they are renamed for what they still cover, a walk that continues across pages. ## Test plan - [x] `test_{sync,async}_walk_reads_nothing_newer_than_the_target` record the rows the walk reads; both fail on main, which also reads the three newer checkpoints. - [x] `checkpoint-postgres` suite on Postgres 16: 281 passed, 3 skipped. - [x] `langgraph` DeltaChannel tests against this saver (`-k "delta and not redis"`): 1,154 passed, 1 skipped. |
||
|
|
bfcfea554e |
fix(checkpoint,checkpoint-postgres,checkpoint-sqlite): validate namespace labels before store dispatch (#9217)
The SQLite and Postgres stores save a namespace as its labels joined
with `.`, so a label containing `.` could resolve to a different
namespace: `("foo.bar",)` and `("foo", "bar")` share the same row. This
rejects those labels at every entry point.
- `BaseStore` and `AsyncBatchedBaseStore`: `get`, `search`, `delete`,
and `list_namespaces` (sync and async) reject labels that are empty, not
strings, or contain `.`. The check runs before an op is queued, so one
caller's bad label can't fail other callers' concurrent requests.
- New `langgraph.store.base.validate_op_namespace(op)` applies the same
label checks to a single op. `SqliteStore`/`AsyncSqliteStore` and
`PostgresStore`/`AsyncPostgresStore` call it from `_group_ops` before
any SQL runs, which covers direct `batch`/`abatch` calls. Other stores
that serialize namespaces as delimited text can call it too.
- Unchanged: hierarchical prefix search, empty-prefix `search(())`, `*`
wildcards in `list_namespaces`, and the existing `put` rules.
## Release note
`get`, `search`, `delete`, and `list_namespaces` now raise
`InvalidNamespaceError` for labels that are empty, not strings, or
contain `.`, where they previously returned `None` or `[]` (or, on the
SQLite and Postgres stores, matched a different namespace). `put`
already rejected these labels, so nothing written through `put` becomes
unreachable.
## Release order
Release `langgraph-checkpoint` first. `langgraph-checkpoint-sqlite` and
`langgraph-checkpoint-postgres` import `validate_op_namespace`, so they
need the `langgraph-checkpoint` release that ships it. `main` already
has `libs/checkpoint` at 4.3.0 and requires
`langgraph-checkpoint>=4.3.0` in both stores (from #8544), so this must
merge before 4.3.0 is released; if 4.3.0 ships first, bump to the next
version and raise both requirements to it. That also guarantees the
pre-queue checks are installed: with an older `langgraph-checkpoint`, an
invalid op would fail inside the shared `abatch` and reject the calls
batched with it.
---------
Co-authored-by: Baihao Wang <byhow@users.noreply.github.com>
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
|
||
|
|
93f5eaff21 |
fix(checkpoint): keep serialized data when an object can't be rebuilt (#9251)
Fixes #6970 If a checkpointed object can't be rebuilt on load (its module was removed or renamed, or its constructor now rejects the stored fields), `JsonPlusSerializer` returned `None` for it, so the value silently disappeared from restored state. The constructor and method ext codes now return the serialized payload instead, the same thing the pydantic and blocked-type paths already do, and log a one-time warning per type. The warning names the exception type only, since exception messages can echo the stored value. Thanks @yangbaechu for the report and repro. This takes the same direction as #6972 by @pandego and #7152 by @SinzoL. |
||
|
|
5965d72ff7 |
fix(langgraph,prebuilt): stop ToolNode from swallowing invalid resume values (#9232)
**Problem.** `interrupt(response_schema=...)` checks a human's answer when the graph resumes. If the answer doesn't match the schema, the resume fails, nothing is saved, and the human can answer again (#8886). That works when the interrupt runs in a graph node, but not when it runs inside a tool: either the tool calls `interrupt()` itself, or it starts a graph that does, such as a subagent called as a tool. There, the resume returns normally and the interrupt disappears. **Why.** `interrupt()` raises a `pydantic.ValidationError` for an invalid answer. When one comes out of a tool, `ToolNode` assumes the model passed bad arguments, so it hands the error to the model ("Error invoking tool … Please fix the error and try again") and the run carries on. The human never sees the error, the model is blamed for it, and the interrupt is no longer pending. **Fix.** `interrupt()` still raises the same `ValidationError`, but marks it so a new helper, `langgraph.errors.is_invalid_resume(error)`, can recognize it. `ToolNode` re-raises these errors instead of handing them to the model, whatever `handle_tool_errors` is set to, so a bad answer fails the resume the same way inside a tool as outside one: nothing is saved and the interrupt can be answered again. Every other `ValidationError` from a tool is handled as before. **Also fixed, in the same error handling.** With `wrap_tool_call` set and a `handle_tool_errors` other than the default (for example `True`), `ToolNode` turned any exception from the wrapper into an error `ToolMessage`, including `GraphInterrupt`. So an interrupt in that setup never paused: the model got `Error: GraphInterrupt(...)` instead. Interrupts now propagate there too, as they already do without a wrapper. `create_agent` uses the default handler, so it was not affected. **Compatibility.** Not a breaking change: the error type is unchanged. Worth a careful look: a wrapped `ToolNode` with a non-default `handle_tool_errors` now pauses on interrupts instead of returning them to the model as errors. With an older `langgraph` that doesn't have `is_invalid_resume`, `ToolNode` keeps today's behavior. |
||
|
|
40a2e6d845 |
fix(langgraph): never store exit-mode delta writes under the null task id (#9229)
In exit mode, a run stores its DeltaChannel writes on the checkpoint it started from, under synthetic task ids that put the superstep first. For a `Command`'s writes in a run whose first superstep is 0, that id came out as `NULL_TASK_ID` itself. Readers take writes under `NULL_TASK_ID` for the checkpoint's own pending writes, so after `invoke(Command(update=...), durability="exit")`: - on a new thread, `get_state` on the empty first checkpoint showed the update in the DeltaChannel but not in a plain channel; - on a thread whose first checkpoint came from `update_state(..., as_node="__input__")`, `get_state` on that checkpoint showed the update the same way, and a replay or fork from it applied the update to the DeltaChannel only. `exit_delta_task_id` now never returns `NULL_TASK_ID`. Threads already saved this way stay as they are. ## Tests - `test_command_update_on_an_input_checkpoint_matches_a_plain_channel` compares every checkpoint in the history, and a replay from the input checkpoint, with a plain channel, on every checkpointer and durability. The exit cases fail without the fix. - `test_exit_command_update_on_a_new_thread_matches_a_plain_channel` compares every checkpoint in a new thread's history with a plain channel, on every checkpointer, and fails without the fix. It runs in exit mode only: in sync and async the two channels already differ on `main`, because of a separate bug that applies a new thread's `Command` update twice. `make format`, `make lint` and the langgraph suite pass. |
||
|
|
a0053bb616 |
fix(sdk-py): end a thread stream's run only on a root lifecycle event (#9228)
The thread stream's lifecycle watcher ended the run on any `completed` or `failed` lifecycle event, including the one a subgraph sends when it finishes. So `thread.output` could read the thread state before the parent stored the step that ran the subgraph, and a run that failed after a subgraph completed was reported as completed. The async and sync watchers now end the run only on a root event, with the `_is_root_terminal_lifecycle` check the fanout already uses. The JS SDK checks the root namespace here too. This is the `sdk-py integration` flake where the final `items` comes back as `['streamed', 'tool', 'asked']` without `'sub'`: the example graph's last node runs a subgraph. ## Tests New async and sync tests send a subgraph `completed` and then a root `failed`. Without the fix the run ends as completed. `make lint` and `make test` in `libs/sdk-py` pass. |
||
|
|
87f1c8eb9a |
fix(langgraph): stop astream_events dropping control/interrupts on v1/v2 (#9219)
### Problem `Pregel.astream_events` declared `interrupt_before`, `interrupt_after` and `control` as keyword-only parameters, but forwarded them only on the `version="v3"` branch. On async `version="v1"`/`"v2"` the values were bound to named parameters and never entered `**kwargs`, so they were silently dropped on the way to `astream` — no error, no effect: - `request_drain()` on a caller-supplied `RunControl` did nothing; the graph created its own control and ran to completion. - Static interrupts passed as `astream_events(..., interrupt_before=[...])` never fired. This is a regression introduced by #7677 (first released in `1.2.0a3`). Before that, `Pregel` did not override `astream_events`, and these keywords reached `astream` through `**kwargs` — langchain-core's v1 and v2 event implementations both forward caller kwargs to `astream` (`tracers/log_stream.py`, `tracers/event_stream.py`). Downstream impact: langgraph-api passes run-level `interrupt_before` / `interrupt_after` into `graph.astream_events(..., version="v2", **kwargs)` for runs with `stream_mode="events"` (`models/run.py`, `stream.py`), so server runs using that stream mode have silently dropped static interrupts since langgraph 1.2.0a3. Sync `stream_events(version="v1"/"v2")` is unaffected: langchain-core raises `NotImplementedError` there, so there was no working sync path to break. ### Fix Remove the three parameters from the public runtime implementations of `stream_events` / `astream_events` (and from the explicit passing in their v3 dispatch calls), so the values travel through `**kwargs` again: - **v1/v2** recover the pre-#7677 passthrough. `astream` receives exactly what the caller passed — a supplied value, an explicit `None`, or nothing for an omitted argument. - **v3** is unchanged. The values bind on `_pregel_stream_v3` / `_apregel_stream_v3`, which keep their named parameters and since-inception (#7519, `1.2.0a1`) explicit-`None` defaults: an omitted argument arrives at `astream` as `None`, exactly as before. What `astream` receives after this change: | caller supplies | async v1/v2 | v3 (sync and async) | |---|---|---| | nothing | argument absent | explicit `None` | | explicit `None` | `None` | `None` | | a value | the value | the value | The typed `version="v3"` `@overload` stubs are untouched, so v3 call sites keep their static types (invalid values still fail `ty` there, same as on `main`). `RemoteGraph` and the v3-only `transformers` parameter are untouched. Complexity: net −24 lines in `main.py` with no branches, sentinels or wrappers added. The public capture-and-drop pattern that caused the bug is gone; the two private helpers each have a single call path and forward unconditionally, so they cannot drop anything. Docstrings now describe the three parameters as honored on every async version (type-checked only on the v3 overloads), and no longer promise synchronous v1/v2 event streaming, which langchain-core does not implement. ### Compatibility notes - The three parameters were keyword-only, so no caller can break; keyword callers bind through `**kwargs` identically. - The names leave the runtime signatures (`inspect.signature`), while the v3 overloads keep the typing. - v3 is unchanged: `_pregel_stream_v3`/`_apregel_stream_v3` still default all three to `None` and pass them explicitly, so an override's non-`None` default never applied on v3 and still doesn't. The only behavior change beyond restoring the pre-#7677 passthrough is on v1/v2 with an explicit `None`: since 1.2.0a3 the named-parameter capture dropped it, so an override's non-`None` default was silently applied instead; now the explicit `None` reaches `astream`, as it did before 1.2.0 and as it does on v3. ### Testing New tests in `tests/test_stream_events_v3_kwarg_forwarding.py`: - `interrupt_before` / `interrupt_after` / pre-drained `control` parametrized over v1/v2/v3 (12 of them fail on unpatched `main`). - Sync v3 static interrupts. - Mid-run drain: a node calls `request_drain()`; asserts `GraphDrained` propagates, the caller's own `RunControl` was used, and the checkpoint keeps the pending step. - Recording tests pin, for all three names and on both the async and sync v3 paths, exactly what `(a)stream` receives: supplied values (with `control` identity), explicit `None`, and absence for omitted arguments. Verified by mutation: replacing the implementation with each rejected alternative (unpatched parent; injecting `None` for omitted kwargs on v1/v2; dropping explicit `None` on v1/v2; kwargs-only private helpers) makes the corresponding tests fail. Suites: 246 passed on the four adjacent streaming test files; 906 passed / 1 skipped across every test file calling `(a)stream_events` plus `test_runtime.py`. `ruff check` / `format --check` clean; `ty check langgraph` clean. Not verifiable locally (CI please): Python 3.10 (the new tests carry no version skip), minimum supported langchain-core, and a live langgraph-api server run. ### Release note > Fixed a regression since 1.2.0a3: `Pregel.astream_events` silently dropped > `interrupt_before`, `interrupt_after` and `control` for > `version="v1"`/`"v2"`. Static interrupts and `RunControl` drains now work on > every async version. Server runs using `stream_mode="events"` were affected > and get their static interrupts back. |
||
|
|
736a18eaab |
release(cli): 0.4.33 (#9227)
Bumping the CLI to 0.4.33 to cut a release including #9221 (deploy listeners list) and #9222 (--image-uri). |
||
|
|
ec4f8535f8 |
feat(cli): add --image-uri to deploy an already-pushed image (#9222)
## Summary `--push-to` always builds (or retags a local `--image`) and pushes, even when the image already exists at the destination. That breaks CI/CD pipelines where the build/push step and the deploy step run in separate jobs: the deploy job has no local copy of the image to retag, and `--image` requires one (it runs `docker image inspect`, which needs the image present in the local Docker daemon). This adds `--image-uri`, which takes a full image reference already in a registry and deploys it directly via `source_revision_config.image_uri`, with no local Docker involvement at all: no inspect, no build, no tag, no push. It gets the same placement behavior as `--push-to` (`--listener-id`/`--k8s-namespace`, or auto-selecting the sole listener) and the same update-in-place semantics, since both produce an `external_docker` deployment and are interchangeable on the same deployment. `--image-uri` requires a digest (`repo@sha256:...`) and rejects empty/blank input. `--push-to` always resolves to a digest after pushing; `--image-uri` has no push step to resolve one from, so a mutable tag (or an unvalidated empty string) could let Kubernetes silently keep running a previously cached image while the CLI reports success. Implementation: `CustomerRegistrySource`'s image-acquisition step is split into two variants, `BuildAndPush` (the existing `--push-to`/`--image` flow, unchanged behavior) and `PublishedImage` (the new flag), so create/update/placement logic stays shared. Also reworded `_ensure_customer_registry_source`'s error, which previously mentioned only `--push-to` even though it's reachable from `--image-uri` too. ## Test plan - [x] `make format && make lint` clean in `libs/cli` - [x] Unit tests in `test_deploy_helpers.py` for `_select_source` selecting `PublishedImage` (by digest, trimmed), requiring no local Docker, carrying placement, and the mutual-exclusivity + validation errors (`--push-to`, `--image`, `--tag`, `--remote`, empty/blank input, missing digest) - [x] CLI-level tests in `test_deploy_command.py`: create and update an external deployment via `--image-uri` with zero Docker calls, listener auto-placement, rejecting a non-external existing deployment (now mentioning both flags), and the conflicting-flag cases end to end - [x] Full `libs/cli` suite: 524 passed, no regressions |
||
|
|
ce14d33687 |
feat(cli): add 'langgraph deploy listeners list' (#9221)
## Summary Originally this auto-selected a workspace's sole listener for self-hosted/hybrid control planes the same way #9056 already does for Cloud. Per review, that's reverted: in self-hosted environments, leaving placement blank is the deliberate signal to deploy to the bundled operator, not an unresolved default. Auto-selecting a sole listener there would silently take that option away from anyone who has both a bundled operator and one listener configured, with no way to get it back. The actual need behind this was simpler: a way to find a listener's id without hardcoding it, so it can be passed to `--listener-id` explicitly. `HostBackendClient.list_listeners()` already existed and is used internally for placement resolution, but had no CLI surface of its own. This adds `langgraph deploy listeners list`, mirroring the existing `deploy list` / `deploy revisions list` pattern, to look up a workspace's listeners and their namespaces. No change to default placement behavior. ## Test plan - [x] `make format && make lint` clean in `libs/cli` - [x] `format_listeners_table` unit test in `test_util.py` - [x] CLI-level tests for `deploy listeners list` (with and without results) in `test_cli.py` - [x] Full `libs/cli` suite: 508 passed, no regressions |
||
|
|
708aaa4ebc |
chore(deps): bump notebook from 7.5.7 to 7.6.3 in /libs/langgraph (#9206)
Bumps [notebook](https://github.com/jupyter/notebook) from 7.5.7 to 7.6.3. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/jupyter/notebook/releases">notebook's releases</a>.</em></p> <blockquote> <h2>v7.6.3</h2> <h2>7.6.3</h2> <p>(<a href="https://github.com/jupyter/notebook/compare/@jupyter-notebook/application-extension@7.6.2...9c8d7c24006554dda8c5fc02c69f91d6449c712a">Full Changelog</a>)</p> <h3>Maintenance and upkeep improvements</h3> <ul> <li>Update to JupyterLab v4.6.4 <a href="https://redirect.github.com/jupyter/notebook/pull/8066">#8066</a> (<a href="https://github.com/jtpio"><code>@jtpio</code></a>)</li> </ul> <h3>Contributors to this release</h3> <p>The following people contributed discussions, new ideas, code and documentation contributions, and review. See <a href="https://github-activity.readthedocs.io/en/latest/use/#how-does-this-tool-define-contributions-in-the-reports">our definition of contributors</a>.</p> <p>(<a href="https://github.com/jupyter/notebook/graphs/contributors?from=2026-08-11&to=2026-09-21&type=c">GitHub contributors page for this release</a>)</p> <p><a href="https://github.com/jtpio"><code>@jtpio</code></a> (<a href="https://github.com/search?q=repo%3Ajupyter%2Fnotebook+involves%3Ajtpio+updated%3A2026-08-11..2026-09-21&type=Issues">activity</a>)</p> <h2>v7.6.2</h2> <h2>7.6.2</h2> <p>(<a href="https://github.com/jupyter/notebook/compare/@jupyter-notebook/application-extension@7.6.1...2f1f1622fc64e09b90ade87ed886fdfe1bc653fb">Full Changelog</a>)</p> <h3>Maintenance and upkeep improvements</h3> <ul> <li>Add nvd.nist.gov to the check_links ignore list <a href="https://redirect.github.com/jupyter/notebook/pull/8032">#8032</a> (<a href="https://github.com/jtpio"><code>@jtpio</code></a>)</li> <li>Backport JupyterLab dependency updater improvements <a href="https://redirect.github.com/jupyter/notebook/pull/8031">#8031</a> (<a href="https://github.com/jtpio"><code>@jtpio</code></a>)</li> <li>Update to JupyterLab v4.6.3 <a href="https://redirect.github.com/jupyter/notebook/pull/8030">#8030</a> (<a href="https://github.com/jtpio"><code>@jtpio</code></a>)</li> <li>Switch local pre-commit hooks to language: system <a href="https://redirect.github.com/jupyter/notebook/pull/8002">#8002</a> (<a href="https://github.com/jtpio"><code>@jtpio</code></a>)</li> </ul> <h3>Documentation improvements</h3> <ul> <li>Update 'notebook v7 proposal' link in doc <a href="https://redirect.github.com/jupyter/notebook/pull/8004">#8004</a> (<a href="https://github.com/brichet"><code>@brichet</code></a>)</li> </ul> <h3>Contributors to this release</h3> <p>The following people contributed discussions, new ideas, code and documentation contributions, and review. See <a href="https://github-activity.readthedocs.io/en/latest/use/#how-does-this-tool-define-contributions-in-the-reports">our definition of contributors</a>.</p> <p>(<a href="https://github.com/jupyter/notebook/graphs/contributors?from=2026-07-22&to=2026-08-11&type=c">GitHub contributors page for this release</a>)</p> <p><a href="https://github.com/brichet"><code>@brichet</code></a> (<a href="https://github.com/search?q=repo%3Ajupyter%2Fnotebook+involves%3Abrichet+updated%3A2026-07-22..2026-08-11&type=Issues">activity</a>) | <a href="https://github.com/jtpio"><code>@jtpio</code></a> (<a href="https://github.com/search?q=repo%3Ajupyter%2Fnotebook+involves%3Ajtpio+updated%3A2026-07-22..2026-08-11&type=Issues">activity</a>)</p> <h2>v7.6.1</h2> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/jupyter/notebook/blob/@jupyter-notebook/tree@7.6.3/CHANGELOG.md">notebook's changelog</a>.</em></p> <blockquote> <h2>7.6.3</h2> <p>(<a href="https://github.com/jupyter/notebook/compare/@jupyter-notebook/application-extension@7.6.2...9c8d7c24006554dda8c5fc02c69f91d6449c712a">Full Changelog</a>)</p> <h3>Maintenance and upkeep improvements</h3> <ul> <li>Update to JupyterLab v4.6.4 <a href="https://redirect.github.com/jupyter/notebook/pull/8066">#8066</a> (<a href="https://github.com/jtpio"><code>@jtpio</code></a>)</li> </ul> <h3>Contributors to this release</h3> <p>The following people contributed discussions, new ideas, code and documentation contributions, and review. See <a href="https://github-activity.readthedocs.io/en/latest/use/#how-does-this-tool-define-contributions-in-the-reports">our definition of contributors</a>.</p> <p>(<a href="https://github.com/jupyter/notebook/graphs/contributors?from=2026-08-11&to=2026-09-21&type=c">GitHub contributors page for this release</a>)</p> <p><a href="https://github.com/jtpio"><code>@jtpio</code></a> (<a href="https://github.com/search?q=repo%3Ajupyter%2Fnotebook+involves%3Ajtpio+updated%3A2026-08-11..2026-09-21&type=Issues">activity</a>)</p> <!-- raw HTML omitted --> <h2>7.6.2</h2> <p>(<a href="https://github.com/jupyter/notebook/compare/@jupyter-notebook/application-extension@7.6.1...2f1f1622fc64e09b90ade87ed886fdfe1bc653fb">Full Changelog</a>)</p> <h3>Maintenance and upkeep improvements</h3> <ul> <li>Add nvd.nist.gov to the check_links ignore list <a href="https://redirect.github.com/jupyter/notebook/pull/8032">#8032</a> (<a href="https://github.com/jtpio"><code>@jtpio</code></a>)</li> <li>Backport JupyterLab dependency updater improvements <a href="https://redirect.github.com/jupyter/notebook/pull/8031">#8031</a> (<a href="https://github.com/jtpio"><code>@jtpio</code></a>)</li> <li>Update to JupyterLab v4.6.3 <a href="https://redirect.github.com/jupyter/notebook/pull/8030">#8030</a> (<a href="https://github.com/jtpio"><code>@jtpio</code></a>)</li> <li>Switch local pre-commit hooks to language: system <a href="https://redirect.github.com/jupyter/notebook/pull/8002">#8002</a> (<a href="https://github.com/jtpio"><code>@jtpio</code></a>)</li> </ul> <h3>Documentation improvements</h3> <ul> <li>Update 'notebook v7 proposal' link in doc <a href="https://redirect.github.com/jupyter/notebook/pull/8004">#8004</a> (<a href="https://github.com/brichet"><code>@brichet</code></a>)</li> </ul> <h3>Contributors to this release</h3> <p>The following people contributed discussions, new ideas, code and documentation contributions, and review. See <a href="https://github-activity.readthedocs.io/en/latest/use/#how-does-this-tool-define-contributions-in-the-reports">our definition of contributors</a>.</p> <p>(<a href="https://github.com/jupyter/notebook/graphs/contributors?from=2026-07-22&to=2026-08-11&type=c">GitHub contributors page for this release</a>)</p> <p><a href="https://github.com/brichet"><code>@brichet</code></a> (<a href="https://github.com/search?q=repo%3Ajupyter%2Fnotebook+involves%3Abrichet+updated%3A2026-07-22..2026-08-11&type=Issues">activity</a>) | <a href="https://github.com/jtpio"><code>@jtpio</code></a> (<a href="https://github.com/search?q=repo%3Ajupyter%2Fnotebook+involves%3Ajtpio+updated%3A2026-07-22..2026-08-11&type=Issues">activity</a>)</p> <h2>7.6.1</h2> <p>(<a href="https://github.com/jupyter/notebook/compare/@jupyter-notebook/application-extension@7.6.0...72c228d76d1a9e5aa81531f7cf3c6af410c5e53f">Full Changelog</a>)</p> <h3>Maintenance and upkeep improvements</h3> <ul> <li>Update to JupyterLab v4.6.2 <a href="https://redirect.github.com/jupyter/notebook/pull/7996">#7996</a> (<a href="https://github.com/jtpio"><code>@jtpio</code></a>)</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/jupyter/notebook/commit/dc710245bf156f11bafc6e7d283695253d6b5cd7"><code>dc71024</code></a> Publish 7.6.3</li> <li><a href="https://github.com/jupyter/notebook/commit/9c8d7c24006554dda8c5fc02c69f91d6449c712a"><code>9c8d7c2</code></a> Update to JupyterLab v4.6.4 (<a href="https://redirect.github.com/jupyter/notebook/issues/8066">#8066</a>)</li> <li><a href="https://github.com/jupyter/notebook/commit/ffc52152951a52ef4885f12521d7a5f8ebd2f9c1"><code>ffc5215</code></a> Publish 7.6.2</li> <li><a href="https://github.com/jupyter/notebook/commit/2f1f1622fc64e09b90ade87ed886fdfe1bc653fb"><code>2f1f162</code></a> Update to JupyterLab v4.6.3 (<a href="https://redirect.github.com/jupyter/notebook/issues/8030">#8030</a>)</li> <li><a href="https://github.com/jupyter/notebook/commit/63df75281ec7226826877f2e77dc68670b109c33"><code>63df752</code></a> Backport JupyterLab dependency updater improvements (<a href="https://redirect.github.com/jupyter/notebook/issues/8031">#8031</a>)</li> <li><a href="https://github.com/jupyter/notebook/commit/66101117b79c92baf364d95647242f490807f18c"><code>6610111</code></a> Backport PR <a href="https://redirect.github.com/jupyter/notebook/issues/8032">#8032</a>: Add nvd.nist.gov to the check_links ignore list (<a href="https://redirect.github.com/jupyter/notebook/issues/8033">#8033</a>)</li> <li><a href="https://github.com/jupyter/notebook/commit/75a02cb28e7ed7a58358b69323be3d9e4800f941"><code>75a02cb</code></a> Backport PR <a href="https://redirect.github.com/jupyter/notebook/issues/8004">#8004</a>: Update 'notebook v7 proposal' link in doc (<a href="https://redirect.github.com/jupyter/notebook/issues/8005">#8005</a>)</li> <li><a href="https://github.com/jupyter/notebook/commit/2b0ebe6584d3f6d59d458a9414f00c985ead4feb"><code>2b0ebe6</code></a> Backport PR <a href="https://redirect.github.com/jupyter/notebook/issues/8002">#8002</a>: Switch local pre-commit hooks to language: system (<a href="https://redirect.github.com/jupyter/notebook/issues/8003">#8003</a>)</li> <li><a href="https://github.com/jupyter/notebook/commit/e058ab3a0d98a4698f201e10d7de723c70150d34"><code>e058ab3</code></a> Publish 7.6.1</li> <li><a href="https://github.com/jupyter/notebook/commit/72c228d76d1a9e5aa81531f7cf3c6af410c5e53f"><code>72c228d</code></a> Update to JupyterLab v4.6.2 (<a href="https://redirect.github.com/jupyter/notebook/issues/7996">#7996</a>)</li> <li>Additional commits viewable in <a href="https://github.com/jupyter/notebook/compare/@jupyter-notebook/tree@7.5.7...@jupyter-notebook/tree@7.6.3">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 show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/langchain-ai/langgraph/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
39c523eb0a |
fix(langgraph): give each bulk_update_state update its own task id (#9128)
`bulk_update_state` stores each update's writes on the checkpoint it
updates, under a task id. An update whose node has no pending task to
reuse got `uuid5(checkpoint_id, INTERRUPT)`, so every such update in one
superstep shared an id. Savers keep one write per `(task_id, idx)`, so
all but the first update's writes were dropped.
Plain channels don't notice, since their value is stored in the new
checkpoint. A `DeltaChannel` rebuilds its value from those writes, so it
lost every update after the first, on memory, sqlite and postgres:
```python
graph.bulk_update_state(config, [[
StateUpdate({"d": ["u1"], "p": ["u1"]}, as_node="a"),
StateUpdate({"d": ["u2"], "p": ["u2"]}, as_node="m"),
]])
# plain: [..., 'u1', 'u2']
# delta: [..., 'u1']
```
The existing multi-update test only passed because it gave each update
an explicit `task_id`, and its docstring said so.
## Fix
The `i`th update gets `uuid5(checkpoint_id, f"{INTERRUPT}:{i}")`. The
first keeps the old id, so a single `update_state` stores exactly what
it did before. Updates that reuse a pending task's id, or pass their
own, are unchanged.
Each update also gets the task path `(__interrupt__, i)`, stored with
its writes. Live execution applies a superstep's updates in the order
given, and a saver that replays a checkpoint's writes by task path
(#8544) now gives them back in that order instead of by task id. Savers
whose `put_writes` takes no `task_path` get the old call.
## Limits
- On savers that order a checkpoint's writes by task id only (the
released ones, until #8544), several updates in one superstep still
replay in task id order.
- langgraphjs has the same shared id in `bulkUpdateState` and loses the
same update; fixed in langchain-ai/langgraphjs#2923 with the same ids.
## Tests
`test_delta_channel_update_state.py` adds sync, async and
next-to-a-pending-task cases across the checkpointer fixtures, with no
explicit task ids, on a thread that already has history (a fresh thread
snapshots every delta channel and hides the bug). All 19 fail on main.
Two more (sync and async) give six updates in one superstep and check
that `get_state` returns them in that order, on a saver that replays by
task path; they fail without the path.
|
||
|
|
3a1796ecf0 |
fix(langgraph): replay a resumed exit-mode run's delta writes in live order (#9114)
Depends on #8544 Resuming an exit-durability run after a parallel interrupt replays the resumed checkpoint's `DeltaChannel` writes wrong: twice on `main`, out of order if the duplicate is simply dropped. `p` finished before `q` interrupted, and `r` runs after `q`: ``` live: ['in1', 'p', 'r'] main, reload: ['in1', 'p', 'r', 'p'] ``` No fork is involved. Any exit-mode run that starts from a checkpoint with pending delta writes hits it: resuming an interrupt, or retrying after a task error. ## Cause Exit durability stores a run's delta writes on the checkpoint it started from, under step-prefixed task ids (`exit_delta_task_id`), so they replay in superstep order. On a resume, that checkpoint already holds the finished tasks' writes under their real task ids. The accumulator stored those loaded writes again under a step-prefixed id, so they replayed twice. Skipping them alone reorders the replay, because the real ids sort after the step-prefixed ones. ## Fix At exit: - writes loaded with the checkpoint are skipped, since they are already stored on it: `NULL_TASK_ID` writes by task id (this run's own `Command` writes are recorded separately in `_first`), the rest by `(task_id, channel)`; - the checkpoint's own superstep keeps its real task paths, so it interleaves with the loaded writes as live execution did, but gets a step-prefixed task id. Under the real id, a resume whose final checkpoint fails to save would leave the resumed task looking done, and the retry would skip it and lose its other writes; - a resume addressed by `checkpoint_id` reruns tasks whose writes are already stored on the checkpoint; their writes to those channels are skipped, and a write to a channel the task did not write before is kept; - later supersteps get task id `ffffffff-<step>-...` and task path `~~<step>...`, which sort after every real task id and every real task path, in step order. So superstep order holds whether a saver orders by task path (#8544) or only by task id. ## Limits - Within the resumed superstep, a saver that orders only by task id replays this run's writes before the ones loaded from the checkpoint. #8544 fixes that for the OSS savers. - If the final checkpoint fails to save, the writes of supersteps after the resumed one stay on the checkpoint and replay once more after the retry (on `main`, every write does). That comes from exit durability storing its writes before its checkpoint, not from this change. ## Tests `test_delta_channel_exit_mode.py`, on the shared checkpointer fixture (memory, sqlite, postgres) in all three durabilities: - resume after a parallel interrupt with a later write, plain and with the head's `checkpoint_id` - the resumed superstep interleaved by task path: `a_asks` resumes after `z_done` finished, and live order puts `a` first - the same runs on a saver that orders writes by task id only - a resume retried after its final checkpoint failed to save - a resume with `Command(resume=..., update=...)` that writes the delta channel replays that write once, in live order - an addressed resume whose rerun task writes a delta channel it did not write before keeps that write The exit cases fail without the change, except the last one, which guards against skipping by task id alone (an earlier version of this PR did); sync and async pass either way. #8548 marked exit durability in `test_resume_on_an_interrupted_head_consumes_its_writes_without_a_snapshot` as a strict expected failure for this bug; this PR drops the mark. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: ErenAta16 <149434812+ErenAta16@users.noreply.github.com> Co-authored-by: ragnarok268 <58264829+ragnarok268@users.noreply.github.com> |
||
|
|
2b93e8b79f |
fix: order delta channel replay by task path (#8544)
Fixes langchain-ai/langgraph#8382 `DeltaChannel` rebuilds its value by replaying ancestor writes through the reducer. Every saver ordered a checkpoint's writes by `(task_id, idx)`, but live execution applies a super-step's writes in task-path order (`apply_writes` sorts tasks by `task_path_str(task.path[:3])`). `task_id` is a hash of the path, so when two or more tasks write one `DeltaChannel` in the same super-step, replay applies them in an arbitrary permutation. Reducers must be batching-invariant, not order-invariant, so the permutation changes the value: `get_state` disagrees with what `invoke` returned, and continuing the thread saves the reordered value as the base for every later write. ## Fix Replay orders by `(task_path, task_id, idx)`, the order `SELECT_PENDING_SENDS_SQL` already uses for sends. `apply_writes` and every saver now sort with one `writes_sort_key` from `langgraph.checkpoint.base`, in Python, so live and replay can't drift apart and don't depend on a database collation. `apply_writes` sorts by the full task path, the string `put_writes` stores, instead of `path[:3]`. The paths that reach `apply_writes` no longer carry task ids, so the live order doesn't change. `BaseCheckpointSaver`'s default `get_delta_channel_history` can't sort by path, since `PendingWrite` has no task path, so it replays each checkpoint's writes in `get_tuple` order. `get_tuple` now has to return `pending_writes` in `writes_sort_key` order, and memory, SQLite and Postgres do, so the default walk is right for any saver that follows that. `AsyncPostgresSaver` also gets the sync `get_delta_channel_history` that `AsyncSqliteSaver` already had; sync reads used to fall back to the default walk. Memory and Postgres already stored `task_path`. SQLite accepted it on `put_writes` and dropped it, so `writes` gains the column and `setup()` adds it to existing databases. Writes without a task path (graph input, `update_state` updates, rows written before the column existed) sort first by `task_id`, which is also where live execution applies input. ## Compatibility - Memory and Postgres already had `task_path` on disk, so existing threads replay in the corrected order after upgrade. - On SQLite, rows from before the upgrade read back as `''` and keep their old order. Only new writes get the corrected order, since there is no stored path to recover. - SQLite has no `ADD COLUMN IF NOT EXISTS`, so `setup()` runs the `ALTER` and treats `duplicate column name` as success, which also covers two processes migrating one file. That error comes while SQLite prepares the statement, before it asks for the write lock, so `setup()` on an up-to-date database doesn't wait on other writers. A read-only database from before the column is read with empty paths instead of failing setup. - Downgrade is safe: older code's `INSERT` omits the column and the column has a default. - `get_tuple` and `list` return `pending_writes` in `writes_sort_key` order instead of task id order (SQLite, Postgres) or put order (memory). Nothing in langgraph depends on the old order. - Postgres reads `task_path` and `idx` with each pending write, so a subclass that pairs `SELECT_SQL` with its own `_load_writes`, or the other way round, has to match the new row shape. - A third-party saver has to replay in `writes_sort_key` order: in its own `get_delta_channel_history` if it has one, otherwise by returning `pending_writes` from `get_tuple` in that order. Otherwise it fails the new conformance tests; the `get_tuple` one is a base test, so it runs for every saver. - langgraph, checkpoint-sqlite and checkpoint-postgres import `writes_sort_key` from langgraph-checkpoint, so this bumps langgraph-checkpoint to 4.3.0 and requires it there. 4.3.0 has to be released first. ## Limits - Several updates in one `bulk_update_state` super-step share a task id, so the saver keeps only the first one's writes and the `DeltaChannel` loses the rest (plain channels are fine). That's on main too; #9128 fixes it and stores a task path per update, so with this PR those updates also replay in the order given. - Exit durability stores its writes differently; resume ordering there is fixed in #9114, stacked on this PR. - langgraphjs applies `DeltaChannel` writes in task id order, live and on replay (langchain-ai/langgraphjs#2544), so its reads match too. Moving JS to task path order is a follow-up. ## Tests Each fails on main and passes here: - `test_delta_channel_parallel_order.py`, across memory, SQLite and Postgres: parallel writers and a `Send` fan-out, comparing `get_state` with the live result, including sync `get_state` on the async savers. - Three conformance tests whose task ids sort opposite to their task paths, so they cannot pass by chance: two on `get_delta_channel_history`, one on `get_tuple`'s `pending_writes` order. - SQLite migration tests from a pre-column database, sync and async, including a read-only file. One more that passes on main too: SQLite `setup()` while another connection holds the write lock, with no busy timeout, sync and async. It keeps the `ALTER` from waiting on that lock. Thanks to @ErenAta16 for the report, the reproduction, and for tracing `task_path` through all three backends, and to @ragnarok268 for the conformance-test design with task ids ordered opposite to their paths. --------- Co-authored-by: ErenAta16 <149434812+ErenAta16@users.noreply.github.com> Co-authored-by: ragnarok268 <58264829+ragnarok268@users.noreply.github.com> |
||
|
|
70dd64065b |
release(langgraph): 1.2.14 (#9215)
Bumps langgraph from 1.2.13 to 1.2.14. Raises the minimum `langgraph-sdk` to 0.4.6, which percent-encodes `thread_id` and `assistant_id` in thread stream requests (#9213). Remote graph streaming uses those thread stream classes, so this keeps it on a version with the fix. Also includes: - Keep DeltaChannel counters on every `update_state` path (#9142) - Keep an `update_state` on an older checkpoint out of its other branches (#9165) - Fork before replaying an update checkpoint the thread moved past (#9170) |
||
|
|
55b0e36c51 |
release(sdk-py): 0.4.6 (#9214)
Bumps the Python SDK version from 0.4.5 to 0.4.6. Percent-encodes `thread_id` and `assistant_id` in thread stream requests (#9213). |
||
|
|
d89c7e100e |
fix(sdk-py): percent-encode thread_id and assistant_id in thread stream requests (#9213)
## Summary
Two REST helpers on the thread stream built their paths by interpolating
the raw identifier:
- `thread.agent.get_tree()` built `/assistants/{assistant_id}/graph`
- the state fetch behind `thread.output` built
`/threads/{thread_id}/state`
httpx collapses `..` segments and treats `#` as a fragment, so an
identifier containing those characters was rewritten into a different
path before the request was sent. Both now go through
`_quote_path_param` in the async and sync stream modules, matching the
other SDK endpoints and the stream transports.
## Tests
`tests/streaming/test_thread_stream_path_encoding.py` drives
`threads.stream(...)` followed by `thread.output` or
`thread.agent.get_tree()`, async and sync, with identifiers containing
`..`, `/`, and `#`. It asserts that the request path keeps each
identifier as a single encoded segment. All four tests fail without the
change.
`make format`, `make lint`, and `make test` pass in `libs/sdk-py`.
|
||
|
|
2d942085e2 |
fix(langgraph): fork before replaying an update checkpoint the thread moved past (#9170)
Depends on #9165 A replay saves a fork checkpoint first, so its writes land on the fork. Two things still reached the checkpoint it replayed from, and through it every branch that already grew from that checkpoint. It skips the fork for an update or fork checkpoint, which is already a branch of its own. Once the thread has moved past such a checkpoint it can have children, and the replay's writes stored on it reach every one of them. Edit a checkpoint, continue from it, then replay the edit, and the branch you continued reads back a write it never ran: ``` plain channel: ['in1', 'a', 'b', 'edit', 'in2', 'a', 'b'] DeltaChannel: ['in1', 'a', 'b', 'edit', 'b', 'in2', 'a', 'b'] ^ the replay's b ``` And a `Command(update=...)` or `Command(goto=...)` replayed from any checkpoint stored its writes there before the run saved its fork. The branches that grew from that checkpoint replayed the update into a `DeltaChannel`, and a later replay of the same checkpoint repeated the old `Command`: the update again, in every channel, or the `goto`'s node again. Both happen on `main`. ## Fix Loading a checkpoint addressed by `checkpoint_id` checks, for update and fork checkpoints only, whether the thread has moved past it, with #9165's `checkpoint_superseded`. If it has, the replay saves its fork checkpoint as it does from any other checkpoint. Subgraphs keep replaying from the edit's parent, as they did without the fork. The run decides on the fork before it stores anything. When it forks, it keeps the `Command`'s writes in memory and applies them, and the fork snapshots the delta channels they write, so the fork carries them and nothing lands on the checkpoint the run addressed. Cost: one extra `get_tuple` when a run addresses an update or fork checkpoint by `checkpoint_id`, such as resuming with the config `update_state` returned. A replay from an edit the thread moved past stores one more checkpoint, and a forked `Command` that writes a delta channel stores a snapshot of it. ## Limits - A `Command(resume=...)` addressed at a checkpoint the thread moved past doesn't fork, so its run's writes still land there, and a branch that grew from that checkpoint without answering the interrupt replays them. Same on `main`. A fork would give the tasks new ids, and interrupt ids and resume-map keys are hashes of the task's namespace, which includes the task id, so a resume map built from the interrupts the caller just read would stop matching. This needs writes that record their branch (#9174). ## Tests `test_delta_channel_fork.py`, on the shared checkpointer fixtures in all durabilities: - replay from an edit the thread moved past, with and without a subgraph, sync and async, with no input and with `Command(update=...)` - a `Command(update=...)` or `Command(goto=...)` replay of a plain checkpoint the thread moved past: the branch that grew from it reads back unchanged, and a later replay of the checkpoint doesn't repeat the `Command` 124 of the 186 cases fail on #9165; the exit ones pass either way. |
||
|
|
456e2b1acc |
fix(langgraph): keep an update_state on an older checkpoint out of its other branches (#9165)
Fixes #8551 `update_state` stores its writes on the checkpoint it addresses. A `DeltaChannel` rebuilds its value by replaying the writes stored on its ancestors, so when that checkpoint already has another child, the edit shows up in that branch too. #8551's repro, editing an earlier turn and then reading the branch that already existed: ``` before the edit: ['in-1', 'first-out', 'in-2', 'second-out'] after the edit: ['in-1', 'first-out', 'patched', 'in-2', 'second-out'] ``` The plain reducer channel in the same graph is unaffected. #8548 already keeps the edited branch itself correct; this is the other direction. ## Fix When `update_state` addresses a checkpoint that is not the thread's latest, the checkpoint it creates snapshots the delta channels the update writes, through the same snapshot #8548 adds for forks, and none of the update's writes are stored on the addressed checkpoint, whatever channels it writes. The edited branch reads the snapshot, and the other branches have nothing new to replay. The addressed checkpoint stays as it was, so a later `as_node=END` update on it doesn't take the edit in, and the edit doesn't show as that checkpoint's task result. On `main` both can happen in any graph, with or without a `DeltaChannel`, and a `DeltaChannel` also takes in the other branch's writes. "Not the latest" is one extra `get_tuple` for the thread, made when the config names a `checkpoint_id`. It compares with the latest put, so a checkpoint that has a child always counts. So does a leaf of an abandoned branch, such as the old head after a fork elsewhere, where nothing could leak; telling the two apart would mean listing the thread, since savers have no lookup by parent. The addressed checkpoint's pending writes can't answer it either: a finished turn that a later run continued from has none, which is #8551's case. Updates on the latest checkpoint are unchanged: no snapshot, same writes. ## Cost Editing an older checkpoint stores one snapshot per delta channel the update writes, the size of that channel's regular snapshot. That includes editing a leaf of an abandoned branch, as above. ## Limits - Threads that already leaked keep the leaked write, since it is stored on the old checkpoint. - The second report in #8551, `RemoveMessage(id=REMOVE_ALL_MESSAGES)` through `_messages_delta_reducer`, is that reducer's documented limit and isn't changed here. ## Tests `test_delta_channel_fork.py`, on the shared checkpointer fixtures: - `update_state` / `aupdate_state` on an older checkpoint, both a finished turn and one whose next node already ran there: the other branch reads back unchanged, and continuing it stays clean - `bulk_update_state` with two supersteps from an older checkpoint - `update_state` with the head's `checkpoint_id` still stores no snapshot - `update_state(None, as_node=END)` on an edited checkpoint: an older one leaves the edit out, also when it wrote only plain channels, and the latest one keeps it in both channels 33 of the 59 cases fail on `main`. The rest pass either way: the head case, the case whose next node already ran, where the saver keeps that node's own write and drops the edit's, and `as_node=END` on the latest checkpoint. Thanks to @AnnaSuSu for the report, the repro, tracing the leak to the writes landing on the addressed checkpoint, and the note that the fix needs a snapshot on the new checkpoint first. --------- Co-authored-by: Wenchao An <64579968+AnnaSuSu@users.noreply.github.com> |
||
|
|
1b84cb0873 |
fix(langgraph): keep DeltaChannel counters on every update_state path (#9142)
`update_state` saves `counters_since_delta_snapshot` on the checkpoint it creates, except on three paths: `update_state(None, as_node=END)`, `as_node="__input__"` and `as_node="__copy__"`. Those save their checkpoint without it, so the next checkpoint restarts every delta channel's counters from zero: ``` before update_state(None, END): [6, 9] after it: (none) after the next run: [2, 3] (with this change: [6, 10], then [8, 13]) ``` The counters decide when a channel snapshots, so after any of these updates the next snapshot comes later than `snapshot_frequency` and reads walk further back. A thread driven only by these updates never snapshots, so its walk keeps growing. The field's docstring says it is absent only on threads that don't use delta channels. ## Fix `END` and `__input__` build their checkpoint with `create_checkpoint_plan_for_update_state_api`, the plan an update as a node already uses, which now takes the checkpoint's `source`. The counters advance by one superstep (`END` counts the channels its absorbed writes touched as updated), and a channel that reaches its bound snapshots right there. `__copy__` saves a checkpoint with the same values on the same parent, so it keeps the copied checkpoint's counters. ## Tests `test_delta_channel_supersteps_bound.py`, sync and async: - each of the three paths saves the base's counters advanced by one superstep (or unchanged for `__copy__`). - `END` and `__input__` snapshot a channel that reaches its supersteps bound. All 10 fail on main. |
||
|
|
8e15e0d0bc |
release(langgraph): 1.2.13 (#9205)
Bumps langgraph from 1.2.12 to 1.2.13. Stops reporting answered interrupts in `get_state()` (#9103, fixes #6956, fixes #8579): latest-state reads now omit interrupts from finished tasks, and `Command(resume=value)` without an interrupt id raises when more than one interrupt is pending. Also fixes DeltaChannel history handling: subgraph delta channels now hydrate with the caller-resolved saver (#8538), an abandoned branch is no longer replayed into a DeltaChannel fork (#8548), and history is no longer walked for a DeltaChannel that was never written (#9141). Dependency updates in `libs/langgraph`: pyjwt 2.13.0 → 2.15.1, urllib3 2.7.0 → 2.8.0, tornado 6.5.8 → 6.5.9, notebook 7.5.6 → 7.5.7. |
||
|
|
524b320e30 |
fix(langgraph): don't walk history for a DeltaChannel that was never written (#9141)
A `DeltaChannel` with no version at a checkpoint was never written, so
its value is empty. `channels_from_checkpoint` still asked the saver for
its history, and with no snapshot to stop at, the walk reads every
ancestor of the thread, on every run and every `get_state`. A channel
that never gets written is common: deepagents' `files` channel when an
agent doesn't use files.
On SQLite the walk fails outright once the thread is long enough,
because stage 2 binds one variable per ancestor. With one never-written
channel on a 33,000-step thread:
```
main: get_state -> OperationalError: too many SQL variables
next run -> OperationalError: too many SQL variables
branch: get_state ok in 1 ms, next run ok
```
## Fix
Only channels that have a version at the checkpoint are walked. A
channel without one hydrates empty without asking the saver.
A version is assigned whenever a channel is written (by a task, an
input, `update_state` or a migration from a plain channel), so no
version means no write on this branch. The walk could only have found
writes this branch never applied.
Snapshotting such a channel instead would also bound the walk, but it
writes a blob for an empty value on every thread. Today
`create_checkpoint` skips any channel without a version, so even the
forced `DELTA_MAX_SUPERSTEPS_SINCE_SNAPSHOT` snapshot never lands for
it, and the walk has no bound.
## Tests
`test_delta_channel_supersteps_bound.py`: a graph whose second delta
channel is never written asks the saver only for the written channel's
history, sync and async. Both fail on main (`asked for [['a', 'b'],
['a', 'b']]`). A third test covers the case the skip must not break: a
delta channel's first write, left pending on an interrupted head before
the channel has a version, lands exactly once on resume. It passes on
main too.
JS twin: langchain-ai/langgraphjs#2927.
|
||
|
|
9a0394d88b |
fix(langgraph): don't replay an abandoned branch into a DeltaChannel fork (#8548)
Fixes #8443 Fixes #9089 A checkpoint keeps the pending writes that produced its child, and nothing records which child consumed them. When a new branch starts from a checkpoint that already has pending writes (going back in time, or new input on an interrupted head), the `DeltaChannel` ancestor walk replays those writes into the new branch too. The live run is correct; only a reload is wrong: ``` fork base: ['in-1', 'first-out'] fork returns: ['in-1', 'first-out', 'in-3', 'third-out'] reload gives: ['in-1', 'first-out', 'in-2', 'in-3', 'third-out'] ^^^^^^ from the branch the fork replaced ``` Plain channels store their full value and are unaffected, so the tests use one as the oracle. ## Fix The first checkpoint of a new branch snapshots the delta channels its base has pending writes for, so the walk stops inside the branch. Only the base's own writes are branch-specific; everything above it is shared history. A base with no pending writes has nothing to leak, so an ordinary turn that addresses the head (as clients commonly do) stores nothing. `bulk_update_state` takes the set from its first superstep only: a `__copy__` is stored under the base's parent, so nothing after it walks the base's writes. A resume that is not replaying reuses the head's pending writes instead of rerunning their tasks, so it seals only the loaded writes that don't go back to their task: a finished task whose `Send` a `Command(goto=...)` replaced, or an error handler that runs again. A plain resume stores nothing. A resume addressed by `checkpoint_id` reruns them, so it still seals. `put` only stores a blob for a channel whose version moved since the last stored checkpoint, so a snapshot of one that didn't move needs a version bump, and scheduling reads versions. `create_checkpoint` therefore advances every `versions_seen` entry that had seen the old version, including the interrupt tracker. Without the advance, the bump re-fires `interrupt_before` on resume and reruns the channel's subscribers. For each entry it advances, `SNAPSHOT_BUMPS` keeps the version the node really read, so `update_state`'s `as_node` inference reads `versions_seen` as if the bump never happened. A never-written channel gets a version only for the seal; the cadence and a fresh thread's first `update_state` skip it. `update_state` no longer records its narrower `updated_channels` when it snapshots; it skipped a deferred node listed in `next` on resume (#9089). The same seal fixes two `update_state` calls on one checkpoint (editing the same message twice): both store their writes there under the same task id, the saver keeps the first, and the second branch read back the first one's edit. Two things this touches were also wrong on `main`: a resumed error handler that runs again left its stored writes on the head (an exit reload read them twice), and `aupdate_state` on a thread seeded only by updates raised "Ambiguous update" where `update_state` applied the update as the input. `update_state` and `aupdate_state` now share one `as_node` inference. Exit durability has a separate replay bug on `main` when a resumed checkpoint already holds writes (duplicated or reordered replay), unrelated to forks. It's fixed in #9114; the resume test here marks exit durability as a strict expected failure until then. `tests/memory_assert.py` now compares against the checkpoint as read back: a delta channel a step didn't write is refilled on read, which the old comparison reported as a mutation. Cost: 300 turns addressing the head store no snapshots, as on `main`. A resume that reruns finished tasks seals every time. After a parallel task finished, 30 turns of resuming with the head's `checkpoint_id` (what Studio sends) stored 30 snapshots, 191 KB, against 12 KB of delta writes, and a subgraph resume with a finished sibling does the same, since a subgraph loop always counts as replaying. That seal is what keeps a rerun task's new write from being replayed as its old one: without it, a subgraph task that returns something different on the rerun reads back its first result. The reruns happen on `main` too, and stopping them would remove this cost. 276 of 464 cases in `test_delta_channel_fork.py` fail on `main` and pass here (memory, sqlite and postgres, all durabilities). #9089's own case is in `test_delta_channel_update_state.py`, the cadence case in `test_delta_channel_supersteps_bound.py`, and the `as_node` cases in `test_pregel.py`. ## Limits - Threads forked before this change keep their state: the ownership was never recorded, so there is nothing to recover. - With exit durability, a fork at a finished turn stores its writes on the shared base, so the original branch then replays them too (`['h1', 'ai', 'h2-edited', 'ai', 'h2', 'ai']`). Same on `main`. - `Command(update=..., goto=...)` sent to an old checkpoint stores the update there, so the original branch replays it too. The fork itself is correct now; the original branch is the same as on `main`. - #8551 (the mirror case: `update_state`'s own writes leaking into the abandoned branch) is fixed in #9165, stacked on this PR. It builds on this snapshot, but keys off whether the addressed checkpoint is the thread's latest rather than on pending writes, which a finished turn that a later run continued from doesn't have. Thanks to @AnnaSuSu for the report, the reproduction and the snapshot approach, and to @UditDewan for the implementation in #8476. Both are co-authors. --------- Co-authored-by: AnnaSuSu <64579968+AnnaSuSu@users.noreply.github.com> Co-authored-by: UditDewan <194863456+UditDewan@users.noreply.github.com> |
||
|
|
7dc9195e41 |
chore(deps): bump notebook from 7.5.6 to 7.5.7 in /libs/langgraph (#9168)
Bumps [notebook](https://github.com/jupyter/notebook) from 7.5.6 to 7.5.7. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/jupyter/notebook/releases">notebook's releases</a>.</em></p> <blockquote> <h2>v7.5.7</h2> <h2>7.5.7</h2> <p>(<a href="https://github.com/jupyter/notebook/compare/@jupyter-notebook/application-extension@7.5.6...af55f111d335315edd9e5eab472c9c1bbbb17b27">Full Changelog</a>)</p> <h3>Maintenance and upkeep improvements</h3> <ul> <li>Pin Node to 22.x in UI tests <a href="https://redirect.github.com/jupyter/notebook/pull/7940">#7940</a> (<a href="https://github.com/jtpio"><code>@jtpio</code></a>)</li> <li>Update to JupyterLab v4.5.8 <a href="https://redirect.github.com/jupyter/notebook/pull/7939">#7939</a> (<a href="https://github.com/jtpio"><code>@jtpio</code></a>)</li> </ul> <h3>Contributors to this release</h3> <p>The following people contributed discussions, new ideas, code and documentation contributions, and review. See <a href="https://github-activity.readthedocs.io/en/latest/use/#how-does-this-tool-define-contributions-in-the-reports">our definition of contributors</a>.</p> <p>(<a href="https://github.com/jupyter/notebook/graphs/contributors?from=2026-04-30&to=2026-06-04&type=c">GitHub contributors page for this release</a>)</p> <p><a href="https://github.com/jtpio"><code>@jtpio</code></a> (<a href="https://github.com/search?q=repo%3Ajupyter%2Fnotebook+involves%3Ajtpio+updated%3A2026-04-30..2026-06-04&type=Issues">activity</a>)</p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/jupyter/notebook/blob/@jupyter-notebook/tree@7.5.7/CHANGELOG.md">notebook's changelog</a>.</em></p> <blockquote> <h2>7.5.7</h2> <p>(<a href="https://github.com/jupyter/notebook/compare/@jupyter-notebook/application-extension@7.5.6...af55f111d335315edd9e5eab472c9c1bbbb17b27">Full Changelog</a>)</p> <h3>Maintenance and upkeep improvements</h3> <ul> <li>Pin Node to 22.x in UI tests <a href="https://redirect.github.com/jupyter/notebook/pull/7940">#7940</a> (<a href="https://github.com/jtpio"><code>@jtpio</code></a>)</li> <li>Update to JupyterLab v4.5.8 <a href="https://redirect.github.com/jupyter/notebook/pull/7939">#7939</a> (<a href="https://github.com/jtpio"><code>@jtpio</code></a>)</li> </ul> <h3>Contributors to this release</h3> <p>The following people contributed discussions, new ideas, code and documentation contributions, and review. See <a href="https://github-activity.readthedocs.io/en/latest/use/#how-does-this-tool-define-contributions-in-the-reports">our definition of contributors</a>.</p> <p>(<a href="https://github.com/jupyter/notebook/graphs/contributors?from=2026-04-30&to=2026-06-04&type=c">GitHub contributors page for this release</a>)</p> <p><a href="https://github.com/jtpio"><code>@jtpio</code></a> (<a href="https://github.com/search?q=repo%3Ajupyter%2Fnotebook+involves%3Ajtpio+updated%3A2026-04-30..2026-06-04&type=Issues">activity</a>)</p> <!-- raw HTML omitted --> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/jupyter/notebook/commit/a25fa5eda09ef85984ddafe4a5def427bf34912b"><code>a25fa5e</code></a> Publish 7.5.7</li> <li><a href="https://github.com/jupyter/notebook/commit/af55f111d335315edd9e5eab472c9c1bbbb17b27"><code>af55f11</code></a> Update to JupyterLab v4.5.8 (<a href="https://redirect.github.com/jupyter/notebook/issues/7939">#7939</a>)</li> <li><a href="https://github.com/jupyter/notebook/commit/1f7059106ebdd038ecd30512295e2d1f77b7d698"><code>1f70591</code></a> Pin Node to 22.x in UI tests to avoid Playwright install hang (<a href="https://redirect.github.com/jupyter/notebook/issues/7940">#7940</a>)</li> <li>See full diff in <a href="https://github.com/jupyter/notebook/compare/@jupyter-notebook/tree@7.5.6...@jupyter-notebook/tree@7.5.7">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 show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/langchain-ai/langgraph/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
1fd716c44a |
chore(deps): bump virtualenv from 21.7.12 to 21.7.13 in /libs/cli (#9167)
Bumps [virtualenv](https://github.com/pypa/virtualenv) from 21.7.12 to 21.7.13. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/pypa/virtualenv/releases">virtualenv's releases</a>.</em></p> <blockquote> <h2>21.7.13</h2> <!-- raw HTML omitted --> <h2>What's Changed</h2> <ul> <li>👷 ci: correct a stale checkout pin comment by <a href="https://github.com/gaborbernat"><code>@gaborbernat</code></a> in <a href="https://redirect.github.com/pypa/virtualenv/pull/3254">pypa/virtualenv#3254</a></li> <li>🔧 chore: drop misc as a changelog fragment type by <a href="https://github.com/gaborbernat"><code>@gaborbernat</code></a> in <a href="https://redirect.github.com/pypa/virtualenv/pull/3255">pypa/virtualenv#3255</a></li> <li>👷 ci: scope the nushell apt key to its own repo by <a href="https://github.com/gaborbernat"><code>@gaborbernat</code></a> in <a href="https://redirect.github.com/pypa/virtualenv/pull/3253">pypa/virtualenv#3253</a></li> <li>🐛 fix(activation): stop path command injection in bash and fish by <a href="https://github.com/gaborbernat"><code>@gaborbernat</code></a> in <a href="https://redirect.github.com/pypa/virtualenv/pull/3252">pypa/virtualenv#3252</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/pypa/virtualenv/compare/21.7.12...21.7.13">https://github.com/pypa/virtualenv/compare/21.7.12...21.7.13</a></p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/pypa/virtualenv/blob/main/docs/changelog.rst">virtualenv's changelog</a>.</em></p> <blockquote> <h1>Bugfixes - 21.7.13</h1> <ul> <li>Fix <code>activate</code> and <code>activate.fish</code> running commands embedded in the virtual environment path or in the interpreter's Tcl/Tk library paths. (:issue:<code>3252</code>)</li> </ul> <hr /> <p>v21.7.12 (2026-09-18)</p> <hr /> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/pypa/virtualenv/commit/0c295ff1a5f298e8e11935e3588f59f7455c1f8f"><code>0c295ff</code></a> release 21.7.13</li> <li><a href="https://github.com/pypa/virtualenv/commit/4d5a105ec2a2723b8c7f4571bb68f4f71d01e3f6"><code>4d5a105</code></a> 🐛 fix(activation): stop path command injection in bash and fish (<a href="https://redirect.github.com/pypa/virtualenv/issues/3252">#3252</a>)</li> <li><a href="https://github.com/pypa/virtualenv/commit/0525dcea21865059ffedc70054f6f982be723992"><code>0525dce</code></a> 👷 ci: scope the nushell apt key to its own repo (<a href="https://redirect.github.com/pypa/virtualenv/issues/3253">#3253</a>)</li> <li><a href="https://github.com/pypa/virtualenv/commit/aa8323a907834e9c16fb734613ce41a6d7e27260"><code>aa8323a</code></a> 🔧 chore: drop misc as a changelog fragment type (<a href="https://redirect.github.com/pypa/virtualenv/issues/3255">#3255</a>)</li> <li><a href="https://github.com/pypa/virtualenv/commit/a43547765e017f3a13f029e24c6e6f73882e15bc"><code>a435477</code></a> 👷 ci: correct a stale checkout pin comment (<a href="https://redirect.github.com/pypa/virtualenv/issues/3254">#3254</a>)</li> <li>See full diff in <a href="https://github.com/pypa/virtualenv/compare/21.7.12...21.7.13">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 show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/langchain-ai/langgraph/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
3af263175f |
fix(langgraph): hydrate subgraph delta channels with the caller-resolved saver (#8538)
Fixes langchain-ai/langgraph#8470 Fixes langchain-ai/langgraph#8653 Reported by @gururafiki, with a self-contained `InMemorySaver` repro and the observation that non-delta channels in the same namespace hydrate fine, which is what makes the failure silent. @doniyor2109 reported #8653, the same missing saver at the root: a graph compiled without a checkpointer, whose saver arrives through the config, read the channel back empty in `get_state`, `get_state_history` and `update_state`. ### The bug, in one read One subgraph state, two channels written by the same nodes: `delta` is a `DeltaChannel`, `plain` is an `operator.add` list. Pause the subgraph before its second node and read it through the documented `get_state(config, subgraphs=True).tasks[0].state`: ``` main: {'delta': [], 'plain': ['a1']} branch: {'delta': ['a1'], 'plain': ['a1']} ``` Same call, same instant, same state object. If this were a rule about how subgraphs manage state, both channels would be empty. Only the delta one is, because it is the one channel type that stores nothing in `channel_values` and has to replay its writes through a saver. ### Why only the delta channel A subgraph has no saver of its own. It either inherits the parent's (the default, "per-invocation") or opts in with `checkpointer=True` ("per-thread"), and in both cases the saver reaches it through `CONFIG_KEY_CHECKPOINTER`. All four public readers resolve it from there. `_prepare_state_snapshot` then ignored that and re-derived the saver from `self.checkpointer`: - per-invocation: `self.checkpointer` is `None` - per-thread: `self.checkpointer` is `True`, and `isinstance(True, BaseCheckpointSaver)` is `False` So the explicit per-thread opt-in, the mode that exists to make subgraph state readable across invocations, was broken too. With no saver the ancestor walk never runs and the channel falls through to `from_checkpoint(MISSING)`: an empty value, indistinguishable from never written, raising nothing. The saver can't be recovered inside the function: `get_state_history` passes the checkpointer's stored config, which never carries a live saver. The caller is the only place it exists, so the caller passes it, as a required keyword argument. ### What stays unchanged The two modes from the [subgraph persistence docs](https://docs.langchain.com/oss/python/langgraph/use-subgraphs#subgraph-persistence) where an empty read is correct are pinned by tests that pass before and after: - `checkpointer=False` persists nothing, so there is no subgraph namespace to read. - after a subgraph completes, `subgraphs=True` has no pending task to attach state to, for every channel type alike. ### The write path loses data on disk `bulk_update_state` / `abulk_update_state` carried the same expression. When an update reaches the channel's snapshot cadence, `create_checkpoint` persists a `_DeltaSnapshot` built from the empty hydration, so `update_state` on a subgraph namespace replaces `['a1', 'b1', 'b2']` with `['manual']` permanently. At the default `snapshot_frequency=1000` no snapshot is written and the loss stays latent; the tests use `snapshot_frequency=2` to reach it. `prepare_next_tasks` in `_prepare_state_snapshot` now receives the same saver too. It was inert there (the task config falls back to `CONFIG_KEY_CHECKPOINTER`, and `PregelTask` exposes no config), but one expression is easier to trust than two. ### One saver lookup and namespace rule The run loop and all six state methods now share one saver lookup (`_resolve_checkpointer`) and one namespace rule for `checkpointer=True` subgraphs, and the state methods find the subgraph a namespaced config addresses through one helper (`_subgraph_for_namespace`). Before, only `get_state` / `aget_state` stripped the task id, so `get_state_history` and `update_state` given the subgraph task's config looked under `name:<task_id>`, where the run never stores anything: the history came back empty and the update was silently lost. The namespace rule strips only the task ids: a task that calls the same `checkpointer=True` subgraph twice stores the second call under `<node>|1`, and `recast_checkpoint_ns` would drop that counter. Sharing the lookup with runs also fixes two places where a state method disagreed with a run: a `checkpointer=False` graph ignores a saver lent through the config, so `update_state` raises "No checkpointer set" instead of writing a checkpoint no run reads, and a `checkpointer=True` graph used as root raises the run's `checkpointer=True cannot be used for root graphs.` instead of an AttributeError. `channels_from_checkpoint` now raises when a `DeltaChannel` has a version but no stored value and no saver or config was passed, so a caller that forgets either fails instead of reading `[]`. Keying on the version keeps a never-written channel reading as empty. ### Verification `tests/test_delta_channel_subgraph.py` runs against the shared `sync_checkpointer` / `async_checkpointer` fixtures (memory, sqlite, postgres), and every assertion compares both channels: | surface | on main | | -- | -- | | `get_state` / `aget_state` on a subgraph ns | `delta: []` | | `get_state_history` / `aget_state_history` | every snapshot `delta: []` | | two levels of nesting | `delta: []` | | `get_state(subgraphs=True)` / async, interrupted, per-invocation and per-thread | `delta: []` | | `update_state` / `aupdate_state` | `delta: ['manual']`, prior history lost | | `get_state_history` / `update_state` from a `checkpointer=True` subgraph's task config, sync and async | no snapshots / update lost | | `channels_from_checkpoint` with a written delta channel and no saver or config | silent `[]` | | `get_state` / `update_state` / `get_state_history` on a graph compiled without a checkpointer, saver lent through the config (#8653), sync and async | `delta: []` | | `get_state` of a `checkpointer=True` subgraph's second call in one task (`node\|1`), sync and async | the first call's state | 159 cases: 144 fail on main, all 159 pass here. The 15 that pass on main are the two unchanged-mode controls and the never-written case. --------- Co-authored-by: gururafiki <22777967+gururafiki@users.noreply.github.com> Co-authored-by: Yuan Gao <119447586+DavidGao520@users.noreply.github.com> |
||
|
|
e6cf9ea667 |
fix(langgraph): stop reporting answered interrupts in get_state (#9103)
Execution, snapshots, and resume checks interpreted the same pending writes separately. When one of several interrupted tasks finished after resuming, `get_state()` still reported its answered question as pending. Use `read_task_statuses()` across execution, state reads, and resume checks. An output write marks a task finished; `RESUME` alone does not, since the task may pause again. Record `NO_WRITES` when a resumed task completes without output, so it isn't run again. Latest-state reads now omit interrupts from finished tasks. History and explicit checkpoint reads still show the last recorded interrupt per task. A task paused at its second interrupt appears in `next` with `result=None`. `Command(resume=value)` without an id now raises when more than one interrupt is pending, including in a subgraph. Threads paused before this change, where a resumed task finished without output, still show that task as unfinished. It appears in `next` and its answered interrupt counts as pending, so if another interrupt is also pending, `Command(resume=value)` without an id raises. Resume these threads by interrupt id. On SQLite and Postgres, insert-ignore can leave an old `RESUME` value for a finished task; that task does not run again. Fixes #6956 Fixes #8579 Thanks to @gautamvarmadatla and @russeell for reporting these. |
||
|
|
157a06dda9 |
chore(deps-dev): bump the minor-and-patch group across 1 directory with 5 updates (#9155)
Bumps the minor-and-patch group with 5 updates in the /libs/langgraph directory: | Package | From | To | | --- | --- | --- | | [langchain-core](https://github.com/langchain-ai/langchain) | `1.6.1` | `1.6.5` | | [pytest-mock](https://github.com/pytest-dev/pytest-mock) | `3.15.1` | `3.16.0` | | [syrupy](https://github.com/syrupy-project/syrupy) | `6.0.0` | `6.1.1` | | [ruff](https://github.com/astral-sh/ruff) | `0.16.5` | `0.16.9` | | [ty](https://github.com/astral-sh/ty) | `0.0.75` | `0.0.84` | Updates `langchain-core` from 1.6.1 to 1.6.5 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/langchain-ai/langchain/releases">langchain-core's releases</a>.</em></p> <blockquote> <h2>langchain-core==1.6.5</h2> <p>Changes since langchain-core==1.6.4</p> <p>release(core): 1.6.5 (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40816">#40816</a>) fix(core): abbreviate long tool IDs in XML buffer strings (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40792">#40792</a>)</p> <h2>langchain-core==1.6.4</h2> <p>Changes since langchain-core==1.6.3</p> <p>release(core): 1.6.4 (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40718">#40718</a>) chore(core): deprecate chat message history (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40711">#40711</a>) chore(deps): bump anyio from 4.12.0 to 4.14.2 in /libs/core (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40634">#40634</a>) chore(deps): bump soupsieve from 2.8.4 to 2.9 in /libs/core (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40574">#40574</a>)</p> <h2>langchain-core==1.6.3</h2> <p>Changes since langchain-core==1.6.2</p> <p>release(core): 1.6.3 (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40407">#40407</a>) feat(core): Allow model name and provider tracing metadata override based on gateway response (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40406">#40406</a>) test(core): cover the deprecated <code>.text()</code> access path (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40243">#40243</a>) docs(core): remove stale Args/Raises entries from FileCallbackHandler._write and ChatGeneration.set_text (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40211">#40211</a>)</p> <h2>langchain-core==1.6.2</h2> <p>Changes since langchain-core==1.6.1</p> <p>release(core): 1.6.2 (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40209">#40209</a>) feat(openai): support async tools (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40208">#40208</a>) chore(deps): bump mistune from 3.3.0 to 3.3.3 in /libs/core (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40150">#40150</a>) chore(deps): bump tornado from 6.5.7 to 6.5.8 in /libs/core (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40113">#40113</a>) fix(core): avoid mutation in google-genai standard content (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40023">#40023</a>) fix(core): avoid mutation in bedrock converse standard content (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40022">#40022</a>)</p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/langchain-ai/langchain/commit/c5ab14d42a3e22865c9def909de0b11d70b0bbf0"><code>c5ab14d</code></a> release(core): 1.6.5 (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40816">#40816</a>)</li> <li><a href="https://github.com/langchain-ai/langchain/commit/5704d9d4813f8c0527f04e2662cf313e1350f96f"><code>5704d9d</code></a> chore(model-profiles): refresh model profile data (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40804">#40804</a>)</li> <li><a href="https://github.com/langchain-ai/langchain/commit/7622d3dce760ac4be6d9aef4c653277e06064aea"><code>7622d3d</code></a> release(openai): 1.6.6 (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40800">#40800</a>)</li> <li><a href="https://github.com/langchain-ai/langchain/commit/2dd956b8add667dac4f97605ae441d75b8ae228e"><code>2dd956b</code></a> docs(infra): fix AGENTS.md root setup guidance and package doc accuracy (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40794">#40794</a>)</li> <li><a href="https://github.com/langchain-ai/langchain/commit/49f4b4016b82513c3dc1623bf3daa10453861621"><code>49f4b40</code></a> fix(openai): raise on error events in stream path (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40791">#40791</a>)</li> <li><a href="https://github.com/langchain-ai/langchain/commit/19cadaa1a1e0cac71f3148e2f18b414dcab17426"><code>19cadaa</code></a> fix(core): abbreviate long tool IDs in XML buffer strings (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40792">#40792</a>)</li> <li><a href="https://github.com/langchain-ai/langchain/commit/798441e8b07e88e79db355db452cd9492f9628f2"><code>798441e</code></a> chore(anthropic): fix integration test cassette (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40790">#40790</a>)</li> <li><a href="https://github.com/langchain-ai/langchain/commit/a476942bac3fe5e521676d0f53fabafcb7ba71b1"><code>a476942</code></a> release(openai): 1.6.5 (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40787">#40787</a>)</li> <li><a href="https://github.com/langchain-ai/langchain/commit/46c6bdf1b4e23028a5acc060d8b2797dbf200291"><code>46c6bdf</code></a> release(anthropic): 1.7.4 (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40786">#40786</a>)</li> <li><a href="https://github.com/langchain-ai/langchain/commit/290dabaff27ee379920d55d155d5055d2fe29cc8"><code>290daba</code></a> fix(anthropic): add Opus 5.5 and GPT-6 profile augmentations (<a href="https://redirect.github.com/langchain-ai/langchain/issues/40785">#40785</a>)</li> <li>Additional commits viewable in <a href="https://github.com/langchain-ai/langchain/compare/langchain-core==1.6.1...langchain-core==1.6.5">compare view</a></li> </ul> </details> <br /> Updates `pytest-mock` from 3.15.1 to 3.16.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/pytest-dev/pytest-mock/releases">pytest-mock's releases</a>.</em></p> <blockquote> <h2>v3.16.0</h2> <p><em>2026-09-27</em></p> <ul> <li><a href="https://redirect.github.com/pytest-dev/pytest-mock/pull/604">#604</a>: Fixed <code>duplicate_iterators=True</code> for async functions spied with <code>mocker.spy</code>.</li> <li><a href="https://redirect.github.com/pytest-dev/pytest-mock/pull/611">#611</a>: Fixed async mock assertion introspection to use awaited arguments instead of the latest call's arguments.</li> <li><a href="https://redirect.github.com/pytest-dev/pytest-mock/pull/606">#606</a>: <code>mocker.resetall(return_value=True, side_effect=True)</code> now also applies to non-callable mocks, such as those returned by <code>mocker.create_autospec(SomeClass, instance=True)</code>. Previously both arguments were silently ignored for them.</li> <li><a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/547">#547</a>: Added <code>SpyType</code> for annotating <code>mocker.spy</code> results.</li> <li>Dropped support for EOL Python 3.9.</li> <li><a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/147">#147</a>: Removed handling of <code>RuntimeError: stop called on unstarted patcher</code>, which can no longer occur in the supported Python versions.</li> <li>Added support for Python 3.15.</li> </ul> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/pytest-dev/pytest-mock/blob/main/CHANGELOG.rst">pytest-mock's changelog</a>.</em></p> <blockquote> <h2>3.16.0</h2> <p><em>2026-09-27</em></p> <ul> <li><code>[#604](https://github.com/pytest-dev/pytest-mock/issues/604) <https://github.com/pytest-dev/pytest-mock/pull/604></code>_: Fixed <code>duplicate_iterators=True</code> for async functions spied with <code>mocker.spy</code>.</li> <li><code>[#611](https://github.com/pytest-dev/pytest-mock/issues/611) <https://github.com/pytest-dev/pytest-mock/pull/611></code>_: Fixed async mock assertion introspection to use awaited arguments instead of the latest call's arguments.</li> <li><code>[#606](https://github.com/pytest-dev/pytest-mock/issues/606) <https://github.com/pytest-dev/pytest-mock/pull/606></code>_: <code>mocker.resetall(return_value=True, side_effect=True)</code> now also applies to non-callable mocks, such as those returned by <code>mocker.create_autospec(SomeClass, instance=True)</code>. Previously both arguments were silently ignored for them.</li> <li><code>[#547](https://github.com/pytest-dev/pytest-mock/issues/547) <https://github.com/pytest-dev/pytest-mock/issues/547></code>_: Added <code>SpyType</code> for annotating <code>mocker.spy</code> results.</li> <li>Dropped support for EOL Python 3.9.</li> <li><code>[#147](https://github.com/pytest-dev/pytest-mock/issues/147) <https://github.com/pytest-dev/pytest-mock/issues/147></code>_: Removed handling of <code>RuntimeError: stop called on unstarted patcher</code>, which can no longer occur in the supported Python versions.</li> <li>Added support for Python 3.15.</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/f3b531f93c6d9837edc87ea1a6f4324dc9a2cdf3"><code>f3b531f</code></a> Release 3.16.0</li> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/71ed67309520be160f3e100368705b58758d237a"><code>71ed673</code></a> Fix duplicate_iterators for async spies (<a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/604">#604</a>)</li> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/0797e3d303cc5bbe0a3514b0625f7aeb3fa350b0"><code>0797e3d</code></a> Fix async assertion argument introspection (<a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/611">#611</a>)</li> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/e24c334d573cfbf6989a31f4e3346676d9d31598"><code>e24c334</code></a> docs: import os in the opening usage example (<a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/612">#612</a>)</li> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/9e7eb7b59cde362c1c8ace2d18ca00fe2d7a1cd1"><code>9e7eb7b</code></a> [pre-commit.ci] pre-commit autoupdate (<a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/613">#613</a>)</li> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/445fd4d3daa8ed4c6d5428a77880da2e03d2f721"><code>445fd4d</code></a> [pre-commit.ci] pre-commit autoupdate (<a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/610">#610</a>)</li> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/a8bd0b147afdf6b4bb1a1a3c3c088f32b0240091"><code>a8bd0b1</code></a> Honour resetall() arguments for non-callable mocks (<a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/606">#606</a>)</li> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/6559fdfd5b67f096423e604a3a5a7045db2486a0"><code>6559fdf</code></a> [pre-commit.ci] pre-commit autoupdate (<a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/608">#608</a>)</li> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/466d026254c949a8fbba8626b894308827be81cf"><code>466d026</code></a> [pre-commit.ci] pre-commit autoupdate (<a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/605">#605</a>)</li> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/164defebde25bc31d53a2a64943c5c9aac43b57e"><code>164defe</code></a> [pre-commit.ci] pre-commit autoupdate (<a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/603">#603</a>)</li> <li>Additional commits viewable in <a href="https://github.com/pytest-dev/pytest-mock/compare/v3.15.1...v3.16.0">compare view</a></li> </ul> </details> <br /> Updates `syrupy` from 6.0.0 to 6.1.1 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/syrupy-project/syrupy/releases">syrupy's releases</a>.</em></p> <blockquote> <h2>v6.1.1</h2> <blockquote> <p><strong>Note:</strong> 6.1.0 was skipped due to a CI issue. Use <strong>6.1.1</strong>.</p> </blockquote> <h3>Experimental <code>--snapshot-file-lock</code> for pytest-xdist</h3> <p><code>--snapshot-update</code> under pytest-xdist can race when multiple workers rewrite the same multi-entry amber (<code>.ambr</code>) file, silently dropping snapshots (<a href="https://redirect.github.com/syrupy-project/syrupy/issues/1237">#1237</a>).</p> <p>This release adds an <strong>experimental</strong> opt-in:</p> <ul> <li><code>--snapshot-file-lock</code> — exclusive file lock + atomic replace around amber writes</li> <li><code>--snapshot-file-lock-timeout</code> — max wait for the lock (default <strong>60s</strong>)</li> </ul> <p>Same-machine workers only; not reliable across remote workers / NFS. See <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1239">#1239</a>.</p> <blockquote> <p><strong>Callout for pytest-xdist users:</strong> please try <code>--snapshot-file-lock</code> with <code>--snapshot-update</code> and <a href="https://github.com/syrupy-project/syrupy/issues">open an issue</a> if you hit problems. Locking is expected to become the default in a future minor release.</p> </blockquote> <h2>New Contributors</h2> <ul> <li><a href="https://github.com/shipbyaeron"><code>@shipbyaeron</code></a> made their first contribution in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1236">syrupy-project/syrupy#1236</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/syrupy-project/syrupy/compare/v6.0.0...v6.1.1">https://github.com/syrupy-project/syrupy/compare/v6.0.0...v6.1.1</a></p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/syrupy-project/syrupy/blob/main/CHANGELOG.md">syrupy's changelog</a>.</em></p> <blockquote> <h2><a href="https://github.com/syrupy-project/syrupy/releases/tag/v6.1.1">v6.1.1</a> (2026-09-13)</h2> <h2>What's Changed</h2> <ul> <li>chore(deps): update dependency ruff to v0.16.4 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1225">syrupy-project/syrupy#1225</a></li> <li>chore(deps): update dependency pytest-benchmark to v5.3.0 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1226">syrupy-project/syrupy#1226</a></li> <li>chore(deps): update dependency ruff to v0.16.5 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1227">syrupy-project/syrupy#1227</a></li> <li>chore(deps): update dependency pydantic to v2.13.5 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1228">syrupy-project/syrupy#1228</a></li> <li>chore(deps): update dependency coverage to v7.16.0 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1229">syrupy-project/syrupy#1229</a></li> <li>chore(deps): update dependency hypothesis to v6.166.0 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1230">syrupy-project/syrupy#1230</a></li> <li>chore(deps): update dependency hypothesis to v6.167.0 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1231">syrupy-project/syrupy#1231</a></li> <li>chore(deps): update dependency hypothesis to v6.167.1 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1232">syrupy-project/syrupy#1232</a></li> <li>chore(deps): update actions/deploy-pages action to v5.0.1 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1234">syrupy-project/syrupy#1234</a></li> <li>chore(deps): update dependency ruff to v0.16.6 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1235">syrupy-project/syrupy#1235</a></li> <li>test: add coverage for read_snapshot_data_from_location returning None by <a href="https://github.com/shipbyaeron"><code>@shipbyaeron</code></a> in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1236">syrupy-project/syrupy#1236</a></li> <li>chore(deps): update dependency hypothesis to v6.168.0 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1238">syrupy-project/syrupy#1238</a></li> <li>fix: opt-in file lock for concurrent amber writes under xdist by <a href="https://github.com/noahnu"><code>@noahnu</code></a> in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1239">syrupy-project/syrupy#1239</a></li> </ul> <h2>New Contributors</h2> <ul> <li><a href="https://github.com/shipbyaeron"><code>@shipbyaeron</code></a> made their first contribution in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1236">syrupy-project/syrupy#1236</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/syrupy-project/syrupy/compare/v6.0.0...v6.1.1">https://github.com/syrupy-project/syrupy/compare/v6.0.0...v6.1.1</a></p> <h2><a href="https://github.com/syrupy-project/syrupy/releases/tag/v6.1.0">v6.1.0</a> (2026-09-13)</h2> <h2>What's Changed</h2> <ul> <li>chore(deps): update dependency ruff to v0.16.4 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1225">syrupy-project/syrupy#1225</a></li> <li>chore(deps): update dependency pytest-benchmark to v5.3.0 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1226">syrupy-project/syrupy#1226</a></li> <li>chore(deps): update dependency ruff to v0.16.5 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1227">syrupy-project/syrupy#1227</a></li> <li>chore(deps): update dependency pydantic to v2.13.5 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1228">syrupy-project/syrupy#1228</a></li> <li>chore(deps): update dependency coverage to v7.16.0 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1229">syrupy-project/syrupy#1229</a></li> <li>chore(deps): update dependency hypothesis to v6.166.0 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1230">syrupy-project/syrupy#1230</a></li> <li>chore(deps): update dependency hypothesis to v6.167.0 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1231">syrupy-project/syrupy#1231</a></li> <li>chore(deps): update dependency hypothesis to v6.167.1 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1232">syrupy-project/syrupy#1232</a></li> <li>chore(deps): update actions/deploy-pages action to v5.0.1 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1234">syrupy-project/syrupy#1234</a></li> <li>chore(deps): update dependency ruff to v0.16.6 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1235">syrupy-project/syrupy#1235</a></li> <li>test: add coverage for read_snapshot_data_from_location returning None by <a href="https://github.com/shipbyaeron"><code>@shipbyaeron</code></a> in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1236">syrupy-project/syrupy#1236</a></li> <li>chore(deps): update dependency hypothesis to v6.168.0 by <a href="https://github.com/renovate"><code>@renovate</code></a>[bot] in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1238">syrupy-project/syrupy#1238</a></li> <li>fix: opt-in file lock for concurrent amber writes under xdist by <a href="https://github.com/noahnu"><code>@noahnu</code></a> in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1239">syrupy-project/syrupy#1239</a></li> </ul> <h2>New Contributors</h2> <ul> <li><a href="https://github.com/shipbyaeron"><code>@shipbyaeron</code></a> made their first contribution in <a href="https://redirect.github.com/syrupy-project/syrupy/pull/1236">syrupy-project/syrupy#1236</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/syrupy-project/syrupy/compare/v6.0.0...v6.1.0">https://github.com/syrupy-project/syrupy/compare/v6.0.0...v6.1.0</a></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/syrupy-project/syrupy/commit/2d251e73f1ebe47fe83ed71d835d3ae8580e8313"><code>2d251e7</code></a> chore(release): 6.1.1 [skip ci]</li> <li><a href="https://github.com/syrupy-project/syrupy/commit/9b64ec05752586c45d1097e9d25f9ee1d4e93219"><code>9b64ec0</code></a> chore(release): 6.1.0 [skip ci]</li> <li><a href="https://github.com/syrupy-project/syrupy/commit/5b4256eac8720075f25b0fa8491f75948001b983"><code>5b4256e</code></a> fix: opt-in file lock for concurrent amber writes under xdist (<a href="https://redirect.github.com/syrupy-project/syrupy/issues/1239">#1239</a>)</li> <li><a href="https://github.com/syrupy-project/syrupy/commit/d4cb1513b5d2b1b18c3b407150db22d2d8604ddd"><code>d4cb151</code></a> chore(deps): update dependency hypothesis to v6.168.0 (<a href="https://redirect.github.com/syrupy-project/syrupy/issues/1238">#1238</a>)</li> <li><a href="https://github.com/syrupy-project/syrupy/commit/16c4cb5b8785d89e49b8076a99f58d810e02fcce"><code>16c4cb5</code></a> test: add coverage for read_snapshot_data_from_location returning None (<a href="https://redirect.github.com/syrupy-project/syrupy/issues/1236">#1236</a>)</li> <li><a href="https://github.com/syrupy-project/syrupy/commit/2e1d3ba0d39a1d87735213a32de9dd9cdb929690"><code>2e1d3ba</code></a> chore(deps): update dependency ruff to v0.16.6 (<a href="https://redirect.github.com/syrupy-project/syrupy/issues/1235">#1235</a>)</li> <li><a href="https://github.com/syrupy-project/syrupy/commit/fcc929d4deb2302f2d37e6511015ef43a0841bc2"><code>fcc929d</code></a> chore(deps): update actions/deploy-pages action to v5.0.1 (<a href="https://redirect.github.com/syrupy-project/syrupy/issues/1234">#1234</a>)</li> <li><a href="https://github.com/syrupy-project/syrupy/commit/4f1bad75777ecc9d916a648dd3669b2844d08f7d"><code>4f1bad7</code></a> chore(deps): update dependency hypothesis to v6.167.1 (<a href="https://redirect.github.com/syrupy-project/syrupy/issues/1232">#1232</a>)</li> <li><a href="https://github.com/syrupy-project/syrupy/commit/24eda28579f5761cbc64713ffcee41cc73602010"><code>24eda28</code></a> chore(deps): update dependency hypothesis to v6.167.0 (<a href="https://redirect.github.com/syrupy-project/syrupy/issues/1231">#1231</a>)</li> <li><a href="https://github.com/syrupy-project/syrupy/commit/0d7e46f9431e07810da4ef90dbe861b85fbc8469"><code>0d7e46f</code></a> chore(deps): update dependency hypothesis to v6.166.0 (<a href="https://redirect.github.com/syrupy-project/syrupy/issues/1230">#1230</a>)</li> <li>Additional commits viewable in <a href="https://github.com/syrupy-project/syrupy/compare/v6.0.0...v6.1.1">compare view</a></li> </ul> </details> <br /> Updates `ruff` from 0.16.5 to 0.16.9 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/astral-sh/ruff/releases">ruff's releases</a>.</em></p> <blockquote> <h2>0.16.9</h2> <h2>Release Notes</h2> <p>Released on 2026-09-24.</p> <h3>Preview features</h3> <ul> <li>[<code>ruff</code>] Avoid false positives for overloaded division (<code>RUF069</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28309">#28309</a>)</li> </ul> <h3>Bug fixes</h3> <ul> <li>[<code>flake8-bugbear</code>] Avoid false positives for calls with keyword arguments (<code>B009</code>, <code>B010</code>, <code>B043</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28776">#28776</a>)</li> <li>[<code>flake8-tidy-imports</code>] Allow lazy imports to be used in deferred annotations (<code>TID255</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28767">#28767</a>)</li> </ul> <h3>Rule changes</h3> <ul> <li>Update LibCST-based fixes for Python 3.15 (<a href="https://redirect.github.com/astral-sh/ruff/pull/28616">#28616</a>)</li> <li>[<code>flake8-pyi</code>] Mention stubs in the diagnostic message (<code>PYI002</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28542">#28542</a>)</li> </ul> <h3>Documentation</h3> <ul> <li>Fix horizontal overflow on the rules documentation page (<a href="https://redirect.github.com/astral-sh/ruff/pull/28699">#28699</a>)</li> <li>Update rules table with category information (<a href="https://redirect.github.com/astral-sh/ruff/pull/28651">#28651</a>)</li> <li>[<code>flake8-annotations</code>] Clarify that <code>ANN401</code> checks return types in addition to arguments (<a href="https://redirect.github.com/astral-sh/ruff/pull/28334">#28334</a>)</li> <li>[<code>flake8-bugbear</code>] Document type-checker interaction (<code>B010</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28509">#28509</a>)</li> <li>[<code>flake8-comprehensions</code>] Document <code>map</code>/generator exception behavior (<code>C417</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/27794">#27794</a>)</li> <li>[<code>ruff</code>] Mention related isort settings (<code>RUF022</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28719">#28719</a>)</li> </ul> <h3>Contributors</h3> <ul> <li><a href="https://github.com/qinpei-dev"><code>@qinpei-dev</code></a></li> <li><a href="https://github.com/sanjayrohith"><code>@sanjayrohith</code></a></li> <li><a href="https://github.com/ntBre"><code>@ntBre</code></a></li> <li><a href="https://github.com/webdevsamran"><code>@webdevsamran</code></a></li> <li><a href="https://github.com/zaniebot"><code>@zaniebot</code></a></li> <li><a href="https://github.com/ewdurbin"><code>@ewdurbin</code></a></li> <li><a href="https://github.com/MichaReiser"><code>@MichaReiser</code></a></li> <li><a href="https://github.com/spaceone"><code>@spaceone</code></a></li> <li><a href="https://github.com/IbrahimKhan12"><code>@IbrahimKhan12</code></a></li> <li><a href="https://github.com/devtechedge"><code>@devtechedge</code></a></li> <li><a href="https://github.com/GruffElixir"><code>@GruffElixir</code></a></li> </ul> <h2>Install ruff 0.16.9</h2> <h3>Install prebuilt binaries via shell script</h3> <pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf https://releases.astral.sh/github/ruff/releases/download/0.16.9/ruff-installer.sh | sh </code></pre> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's changelog</a>.</em></p> <blockquote> <h2>0.16.9</h2> <p>Released on 2026-09-24.</p> <h3>Preview features</h3> <ul> <li>[<code>ruff</code>] Avoid false positives for overloaded division (<code>RUF069</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28309">#28309</a>)</li> </ul> <h3>Bug fixes</h3> <ul> <li>[<code>flake8-bugbear</code>] Avoid false positives for calls with keyword arguments (<code>B009</code>, <code>B010</code>, <code>B043</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28776">#28776</a>)</li> <li>[<code>flake8-tidy-imports</code>] Allow lazy imports to be used in deferred annotations (<code>TID255</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28767">#28767</a>)</li> </ul> <h3>Rule changes</h3> <ul> <li>Update LibCST-based fixes for Python 3.15 (<a href="https://redirect.github.com/astral-sh/ruff/pull/28616">#28616</a>)</li> <li>[<code>flake8-pyi</code>] Mention stubs in the diagnostic message (<code>PYI002</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28542">#28542</a>)</li> </ul> <h3>Documentation</h3> <ul> <li>Fix horizontal overflow on the rules documentation page (<a href="https://redirect.github.com/astral-sh/ruff/pull/28699">#28699</a>)</li> <li>Update rules table with category information (<a href="https://redirect.github.com/astral-sh/ruff/pull/28651">#28651</a>)</li> <li>[<code>flake8-annotations</code>] Clarify that <code>ANN401</code> checks return types in addition to arguments (<a href="https://redirect.github.com/astral-sh/ruff/pull/28334">#28334</a>)</li> <li>[<code>flake8-bugbear</code>] Document type-checker interaction (<code>B010</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28509">#28509</a>)</li> <li>[<code>flake8-comprehensions</code>] Document <code>map</code>/generator exception behavior (<code>C417</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/27794">#27794</a>)</li> <li>[<code>ruff</code>] Mention related isort settings (<code>RUF022</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28719">#28719</a>)</li> </ul> <h3>Contributors</h3> <ul> <li><a href="https://github.com/qinpei-dev"><code>@qinpei-dev</code></a></li> <li><a href="https://github.com/sanjayrohith"><code>@sanjayrohith</code></a></li> <li><a href="https://github.com/ntBre"><code>@ntBre</code></a></li> <li><a href="https://github.com/webdevsamran"><code>@webdevsamran</code></a></li> <li><a href="https://github.com/zaniebot"><code>@zaniebot</code></a></li> <li><a href="https://github.com/ewdurbin"><code>@ewdurbin</code></a></li> <li><a href="https://github.com/MichaReiser"><code>@MichaReiser</code></a></li> <li><a href="https://github.com/spaceone"><code>@spaceone</code></a></li> <li><a href="https://github.com/IbrahimKhan12"><code>@IbrahimKhan12</code></a></li> <li><a href="https://github.com/devtechedge"><code>@devtechedge</code></a></li> <li><a href="https://github.com/GruffElixir"><code>@GruffElixir</code></a></li> </ul> <h2>0.16.8</h2> <p>Released on 2026-09-16.</p> <h3>Bug fixes</h3> <ul> <li>Visit functional <code>TypedDict</code> keyword arguments correctly (<a href="https://redirect.github.com/astral-sh/ruff/pull/28584">#28584</a>)</li> <li>[<code>flake8-simplify</code>] Detect nested <code>async with</code> under sync parent (<code>SIM117</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/27821">#27821</a>)</li> <li>[<code>flake8-simplify</code>] Preserve operand order in <code>SIM109</code> fix (<a href="https://redirect.github.com/astral-sh/ruff/pull/27824">#27824</a>)</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/astral-sh/ruff/commit/0be08a206f9c3180afd3e93bcc792ed5cb1f4db1"><code>0be08a2</code></a> Bump version to 0.16.9 (<a href="https://redirect.github.com/astral-sh/ruff/issues/28882">#28882</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/b4920b72b354e7c715ab861ae23458874683bb02"><code>b4920b7</code></a> Rename <code>ruff_cli</code> to <code>ruff_command_line</code> (<a href="https://redirect.github.com/astral-sh/ruff/issues/28881">#28881</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/47c751b95908a4d1f95f9ef8723036aae9da0b18"><code>47c751b</code></a> Update dependency astral-sh/uv to v0.12.18 (<a href="https://redirect.github.com/astral-sh/ruff/issues/28880">#28880</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/8c244e56a1aeac31c26d2371ef26588e0632235c"><code>8c244e5</code></a> [<code>flake8-comprehensions</code>] Document <code>map</code>/generator exception behavior (<code>C417</code>...</li> <li><a href="https://github.com/astral-sh/ruff/commit/5edf5a1d0a84663079e46983216059f06acea87d"><code>5edf5a1</code></a> Use <code>target</code> form in <code>rooster.version_files</code> (<a href="https://redirect.github.com/astral-sh/ruff/issues/28876">#28876</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/915bb2b4bf9ae7eee47cf55646bbfebae254a23b"><code>915bb2b</code></a> [ty] Prefer existing @ paths over response files in Ruff and ty (<a href="https://redirect.github.com/astral-sh/ruff/issues/28877">#28877</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/4710e1aa962b13720cf64aa84eb279c5333896d7"><code>4710e1a</code></a> ci(github): update version number in placeholder of issue template (<a href="https://redirect.github.com/astral-sh/ruff/issues/28871">#28871</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/eedfc62a75bf1ba86d48959b00eea75ae87eadca"><code>eedfc62</code></a> [ty] Propagate outer type context through cast calls (<a href="https://redirect.github.com/astral-sh/ruff/issues/28855">#28855</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/ceaa6a00830e1e350b8a23977a1a10ac467920a1"><code>ceaa6a0</code></a> [ty] Contain rendered code within Markdown fences (<a href="https://redirect.github.com/astral-sh/ruff/issues/28869">#28869</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/dba0f30615424b94f94a174bba6ce6cce4bf11ff"><code>dba0f30</code></a> authorize ruff-pre-commit dispatch via OIDC (<a href="https://redirect.github.com/astral-sh/ruff/issues/28867">#28867</a>)</li> <li>Additional commits viewable in <a href="https://github.com/astral-sh/ruff/compare/0.16.5...0.16.9">compare view</a></li> </ul> </details> <br /> Updates `ty` from 0.0.75 to 0.0.84 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/astral-sh/ty/releases">ty's releases</a>.</em></p> <blockquote> <h2>0.0.84</h2> <h2>Release Notes</h2> <p>Released on 2026-09-24.</p> <p>This release addresses <a href="https://github.com/astral-sh/ty/security/advisories/GHSA-vxvm-j4xq-q7m4">GHSA-vxvm-j4xq-q7m4</a>, a use-after-free vulnerability during incremental type checking that can result in arbitrary code execution when analyzing a specially crafted Python project. Users who run ty on untrusted code should upgrade to 0.0.84 or newer.</p> <h3>Bug fixes</h3> <ul> <li>Fix stale diagnostics from the LSP server after toggling <code>showSyntaxErrors</code> (<a href="https://redirect.github.com/astral-sh/ruff/pull/28759">#28759</a>)</li> </ul> <h3>LSP server</h3> <ul> <li>Complete string keys from dictionary initializers (<a href="https://redirect.github.com/astral-sh/ruff/pull/28820">#28820</a>)</li> <li>Support LSP requests against closed documents (<a href="https://redirect.github.com/astral-sh/ruff/pull/28595">#28595</a>)</li> <li>Select projects for external files using import search paths (<a href="https://redirect.github.com/astral-sh/ruff/pull/28594">#28594</a>)</li> <li>Use workspace editor settings for external files (<a href="https://redirect.github.com/astral-sh/ruff/pull/28639">#28639</a>)</li> </ul> <h3>Performance</h3> <ul> <li>Avoid repeated subtyping checks for materialized recursive protocols (<a href="https://redirect.github.com/astral-sh/ruff/pull/28774">#28774</a>)</li> <li>Skip reading notebooks when discovering scripts (<a href="https://redirect.github.com/astral-sh/ruff/pull/28781">#28781</a>)</li> </ul> <h3>Core type checking</h3> <ul> <li>Avoid incorrect simplification of <code>TypeIs</code> materializations (<a href="https://redirect.github.com/astral-sh/ruff/pull/28817">#28817</a>)</li> <li>Fix disjointness of generic class types (<a href="https://redirect.github.com/astral-sh/ruff/pull/28787">#28787</a>)</li> <li>Fix staticmethod shadowing through generic receivers and unions (<a href="https://redirect.github.com/astral-sh/ruff/pull/28766">#28766</a>)</li> <li>Infer callable signatures from bounded type variables (<a href="https://redirect.github.com/astral-sh/ruff/pull/28599">#28599</a>)</li> <li>Infer constant membership in inline list and set literals (e.g. <code>"foo" in ["foo"]</code> is now inferred as <code>Literal[True]</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28676">#28676</a>)</li> <li>Infer through optional generic containers in the legacy solver (<a href="https://redirect.github.com/astral-sh/ruff/pull/28791">#28791</a>)</li> <li>Preserve call narrowing during cyclic inference (<a href="https://redirect.github.com/astral-sh/ruff/pull/28708">#28708</a>)</li> <li>Preserve intersections of type guard return types (<a href="https://redirect.github.com/astral-sh/ruff/pull/28796">#28796</a>)</li> <li>Use subtyping for constraint-set implication (<a href="https://redirect.github.com/astral-sh/ruff/pull/28657">#28657</a>)</li> </ul> <h3>Configuration</h3> <ul> <li>Disable <code>invalid-legacy-positional-parameter</code> by default (<a href="https://redirect.github.com/astral-sh/ruff/pull/28834">#28834</a>)</li> </ul> <h3>Other changes</h3> <ul> <li>Only consider reachable definitions when determining whether a condition should be exempted from <code>redundant-condition(-strict)</code> due to the condition being defined relative to <code>sys.version_info</code>, <code>sys.platform</code>, <code>os.name</code> or <code>typing.TYPE_CHECKING</code> (<a href="https://redirect.github.com/astral-sh/ruff/pull/28788">#28788</a>)</li> </ul> <h3>Contributors</h3> <ul> <li><a href="https://github.com/ibraheemdev"><code>@ibraheemdev</code></a></li> <li><a href="https://github.com/zsol"><code>@zsol</code></a></li> <li><a href="https://github.com/charliermarsh"><code>@charliermarsh</code></a></li> <li><a href="https://github.com/lerebear"><code>@lerebear</code></a></li> <li><a href="https://github.com/MichaReiser"><code>@MichaReiser</code></a></li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/astral-sh/ty/blob/main/CHANGELOG.md">ty's changelog</a>.</em></p> <blockquote> <h2>0.0.84</h2> <p>Released on 2026-09-24.</p> <p>This release addresses <a href="https://github.com/astral-sh/ty/security/advisories/GHSA-vxvm-j4xq-q7m4">GHSA-vxvm-j4xq-q7m4</a>, a use-after-free vulnerability during incremental type checking that can result in arbitrary code execution when analyzing a specially crafted Python project. Users who run ty on untrusted code should upgrade to 0.0.84 or newer.</p> <h3>Bug fixes</h3> <ul> <li>Fix stale diagnostics from the LSP server after toggling <code>showSyntaxErrors</code> (<a href="https://redirect.github.com/astral-sh/ruff/pull/28759">#28759</a>)</li> </ul> <h3>LSP server</h3> <ul> <li>Complete string keys from dictionary initializers (<a href="https://redirect.github.com/astral-sh/ruff/pull/28820">#28820</a>)</li> <li>Support LSP requests against closed documents (<a href="https://redirect.github.com/astral-sh/ruff/pull/28595">#28595</a>)</li> <li>Select projects for external files using import search paths (<a href="https://redirect.github.com/astral-sh/ruff/pull/28594">#28594</a>)</li> <li>Use workspace editor settings for external files (<a href="https://redirect.github.com/astral-sh/ruff/pull/28639">#28639</a>)</li> </ul> <h3>Performance</h3> <ul> <li>Avoid repeated subtyping checks for materialized recursive protocols (<a href="https://redirect.github.com/astral-sh/ruff/pull/28774">#28774</a>)</li> <li>Skip reading notebooks when discovering scripts (<a href="https://redirect.github.com/astral-sh/ruff/pull/28781">#28781</a>)</li> </ul> <h3>Core type checking</h3> <ul> <li>Avoid incorrect simplification of <code>TypeIs</code> materializations (<a href="https://redirect.github.com/astral-sh/ruff/pull/28817">#28817</a>)</li> <li>Fix disjointness of generic class types (<a href="https://redirect.github.com/astral-sh/ruff/pull/28787">#28787</a>)</li> <li>Fix staticmethod shadowing through generic receivers and unions (<a href="https://redirect.github.com/astral-sh/ruff/pull/28766">#28766</a>)</li> <li>Infer callable signatures from bounded type variables (<a href="https://redirect.github.com/astral-sh/ruff/pull/28599">#28599</a>)</li> <li>Infer constant membership in inline list and set literals (e.g. <code>"foo" in ["foo"]</code> is now inferred as <code>Literal[True]</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28676">#28676</a>)</li> <li>Infer through optional generic containers in the legacy solver (<a href="https://redirect.github.com/astral-sh/ruff/pull/28791">#28791</a>)</li> <li>Preserve call narrowing during cyclic inference (<a href="https://redirect.github.com/astral-sh/ruff/pull/28708">#28708</a>)</li> <li>Preserve intersections of type guard return types (<a href="https://redirect.github.com/astral-sh/ruff/pull/28796">#28796</a>)</li> <li>Use subtyping for constraint-set implication (<a href="https://redirect.github.com/astral-sh/ruff/pull/28657">#28657</a>)</li> </ul> <h3>Configuration</h3> <ul> <li>Disable <code>invalid-legacy-positional-parameter</code> by default (<a href="https://redirect.github.com/astral-sh/ruff/pull/28834">#28834</a>)</li> </ul> <h3>Other changes</h3> <ul> <li>Only consider reachable definitions when determining whether a condition should be exempted from <code>redundant-condition(-strict)</code> due to the condition being defined relative to <code>sys.version_info</code>, <code>sys.platform</code>, <code>os.name</code> or <code>typing.TYPE_CHECKING</code> (<a href="https://redirect.github.com/astral-sh/ruff/pull/28788">#28788</a>)</li> </ul> <h3>Contributors</h3> <ul> <li><a href="https://github.com/ibraheemdev"><code>@ibraheemdev</code></a></li> <li><a href="https://github.com/zsol"><code>@zsol</code></a></li> <li><a href="https://github.com/charliermarsh"><code>@charliermarsh</code></a></li> <li><a href="https://github.com/lerebear"><code>@lerebear</code></a></li> <li><a href="https://github.com/MichaReiser"><code>@MichaReiser</code></a></li> <li><a href="https://github.com/ewdurbin"><code>@ewdurbin</code></a></li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/astral-sh/ty/commit/8dd9a7f7fa35a18275d82117e6593ba45507065f"><code>8dd9a7f</code></a> Bump version to 0.0.84 (<a href="https://redirect.github.com/astral-sh/ty/issues/4585">#4585</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/d4e4bf90906c7677049bc3a29d1735de7d22052d"><code>d4e4bf9</code></a> publish to astral-sh/versions via OIDC (<a href="https://redirect.github.com/astral-sh/ty/issues/4581">#4581</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/94ce7333abb356b2068dc98d37a68c993da6d09b"><code>94ce733</code></a> use oidc issued token for docs publication (<a href="https://redirect.github.com/astral-sh/ty/issues/4579">#4579</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/901eeaa9cd9ac06f34e85e4f721f76a0dc36e217"><code>901eeaa</code></a> Update prek dependencies (<a href="https://redirect.github.com/astral-sh/ty/issues/4576">#4576</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/09bf0b1b2114a628f3e2296d3d9d28245066c98b"><code>09bf0b1</code></a> Update docker/setup-buildx-action action to v4.3.0 (<a href="https://redirect.github.com/astral-sh/ty/issues/4575">#4575</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/89d6ffe529dd44f64adc0d28f80744b7c7ab217f"><code>89d6ffe</code></a> Update astral-sh/setup-uv action to v10.2.0 (<a href="https://redirect.github.com/astral-sh/ty/issues/4574">#4574</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/9c214798cfcc59069e986876564638fadf32d774"><code>9c21479</code></a> Bump version to 0.0.83 (<a href="https://redirect.github.com/astral-sh/ty/issues/4569">#4569</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/04c69110b391e96310e6892cbed9936c4f31d7aa"><code>04c6911</code></a> Sync the ty security mirror (<a href="https://redirect.github.com/astral-sh/ty/issues/4549">#4549</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/3fa57a25767c619dbeba697c2acfbb8eb291519a"><code>3fa57a2</code></a> Grant the versions workflow repository read access (<a href="https://redirect.github.com/astral-sh/ty/issues/4550">#4550</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/a15b35389b44db57f718fd4e19e093481747c53e"><code>a15b353</code></a> use scoped token for release workflow (<a href="https://redirect.github.com/astral-sh/ty/issues/4506">#4506</a>)</li> <li>Additional commits viewable in <a href="https://github.com/astral-sh/ty/compare/0.0.75...0.0.84">compare view</a></li> </ul> </details> <br /> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: John Kennedy <jkennedyvz@users.noreply.github.com> Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com> |
||
|
|
5204e60579 |
chore(deps-dev): bump the minor-and-patch group in /libs/checkpoint-sqlite with 3 updates (#9146)
Bumps the minor-and-patch group in /libs/checkpoint-sqlite with 3 updates: [pytest-mock](https://github.com/pytest-dev/pytest-mock), [ruff](https://github.com/astral-sh/ruff) and [ty](https://github.com/astral-sh/ty). Updates `pytest-mock` from 3.15.1 to 3.16.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/pytest-dev/pytest-mock/releases">pytest-mock's releases</a>.</em></p> <blockquote> <h2>v3.16.0</h2> <p><em>2026-09-27</em></p> <ul> <li><a href="https://redirect.github.com/pytest-dev/pytest-mock/pull/604">#604</a>: Fixed <code>duplicate_iterators=True</code> for async functions spied with <code>mocker.spy</code>.</li> <li><a href="https://redirect.github.com/pytest-dev/pytest-mock/pull/611">#611</a>: Fixed async mock assertion introspection to use awaited arguments instead of the latest call's arguments.</li> <li><a href="https://redirect.github.com/pytest-dev/pytest-mock/pull/606">#606</a>: <code>mocker.resetall(return_value=True, side_effect=True)</code> now also applies to non-callable mocks, such as those returned by <code>mocker.create_autospec(SomeClass, instance=True)</code>. Previously both arguments were silently ignored for them.</li> <li><a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/547">#547</a>: Added <code>SpyType</code> for annotating <code>mocker.spy</code> results.</li> <li>Dropped support for EOL Python 3.9.</li> <li><a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/147">#147</a>: Removed handling of <code>RuntimeError: stop called on unstarted patcher</code>, which can no longer occur in the supported Python versions.</li> <li>Added support for Python 3.15.</li> </ul> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/pytest-dev/pytest-mock/blob/main/CHANGELOG.rst">pytest-mock's changelog</a>.</em></p> <blockquote> <h2>3.16.0</h2> <p><em>2026-09-27</em></p> <ul> <li><code>[#604](https://github.com/pytest-dev/pytest-mock/issues/604) <https://github.com/pytest-dev/pytest-mock/pull/604></code>_: Fixed <code>duplicate_iterators=True</code> for async functions spied with <code>mocker.spy</code>.</li> <li><code>[#611](https://github.com/pytest-dev/pytest-mock/issues/611) <https://github.com/pytest-dev/pytest-mock/pull/611></code>_: Fixed async mock assertion introspection to use awaited arguments instead of the latest call's arguments.</li> <li><code>[#606](https://github.com/pytest-dev/pytest-mock/issues/606) <https://github.com/pytest-dev/pytest-mock/pull/606></code>_: <code>mocker.resetall(return_value=True, side_effect=True)</code> now also applies to non-callable mocks, such as those returned by <code>mocker.create_autospec(SomeClass, instance=True)</code>. Previously both arguments were silently ignored for them.</li> <li><code>[#547](https://github.com/pytest-dev/pytest-mock/issues/547) <https://github.com/pytest-dev/pytest-mock/issues/547></code>_: Added <code>SpyType</code> for annotating <code>mocker.spy</code> results.</li> <li>Dropped support for EOL Python 3.9.</li> <li><code>[#147](https://github.com/pytest-dev/pytest-mock/issues/147) <https://github.com/pytest-dev/pytest-mock/issues/147></code>_: Removed handling of <code>RuntimeError: stop called on unstarted patcher</code>, which can no longer occur in the supported Python versions.</li> <li>Added support for Python 3.15.</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/f3b531f93c6d9837edc87ea1a6f4324dc9a2cdf3"><code>f3b531f</code></a> Release 3.16.0</li> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/71ed67309520be160f3e100368705b58758d237a"><code>71ed673</code></a> Fix duplicate_iterators for async spies (<a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/604">#604</a>)</li> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/0797e3d303cc5bbe0a3514b0625f7aeb3fa350b0"><code>0797e3d</code></a> Fix async assertion argument introspection (<a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/611">#611</a>)</li> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/e24c334d573cfbf6989a31f4e3346676d9d31598"><code>e24c334</code></a> docs: import os in the opening usage example (<a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/612">#612</a>)</li> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/9e7eb7b59cde362c1c8ace2d18ca00fe2d7a1cd1"><code>9e7eb7b</code></a> [pre-commit.ci] pre-commit autoupdate (<a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/613">#613</a>)</li> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/445fd4d3daa8ed4c6d5428a77880da2e03d2f721"><code>445fd4d</code></a> [pre-commit.ci] pre-commit autoupdate (<a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/610">#610</a>)</li> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/a8bd0b147afdf6b4bb1a1a3c3c088f32b0240091"><code>a8bd0b1</code></a> Honour resetall() arguments for non-callable mocks (<a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/606">#606</a>)</li> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/6559fdfd5b67f096423e604a3a5a7045db2486a0"><code>6559fdf</code></a> [pre-commit.ci] pre-commit autoupdate (<a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/608">#608</a>)</li> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/466d026254c949a8fbba8626b894308827be81cf"><code>466d026</code></a> [pre-commit.ci] pre-commit autoupdate (<a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/605">#605</a>)</li> <li><a href="https://github.com/pytest-dev/pytest-mock/commit/164defebde25bc31d53a2a64943c5c9aac43b57e"><code>164defe</code></a> [pre-commit.ci] pre-commit autoupdate (<a href="https://redirect.github.com/pytest-dev/pytest-mock/issues/603">#603</a>)</li> <li>Additional commits viewable in <a href="https://github.com/pytest-dev/pytest-mock/compare/v3.15.1...v3.16.0">compare view</a></li> </ul> </details> <br /> Updates `ruff` from 0.16.5 to 0.16.9 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/astral-sh/ruff/releases">ruff's releases</a>.</em></p> <blockquote> <h2>0.16.9</h2> <h2>Release Notes</h2> <p>Released on 2026-09-24.</p> <h3>Preview features</h3> <ul> <li>[<code>ruff</code>] Avoid false positives for overloaded division (<code>RUF069</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28309">#28309</a>)</li> </ul> <h3>Bug fixes</h3> <ul> <li>[<code>flake8-bugbear</code>] Avoid false positives for calls with keyword arguments (<code>B009</code>, <code>B010</code>, <code>B043</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28776">#28776</a>)</li> <li>[<code>flake8-tidy-imports</code>] Allow lazy imports to be used in deferred annotations (<code>TID255</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28767">#28767</a>)</li> </ul> <h3>Rule changes</h3> <ul> <li>Update LibCST-based fixes for Python 3.15 (<a href="https://redirect.github.com/astral-sh/ruff/pull/28616">#28616</a>)</li> <li>[<code>flake8-pyi</code>] Mention stubs in the diagnostic message (<code>PYI002</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28542">#28542</a>)</li> </ul> <h3>Documentation</h3> <ul> <li>Fix horizontal overflow on the rules documentation page (<a href="https://redirect.github.com/astral-sh/ruff/pull/28699">#28699</a>)</li> <li>Update rules table with category information (<a href="https://redirect.github.com/astral-sh/ruff/pull/28651">#28651</a>)</li> <li>[<code>flake8-annotations</code>] Clarify that <code>ANN401</code> checks return types in addition to arguments (<a href="https://redirect.github.com/astral-sh/ruff/pull/28334">#28334</a>)</li> <li>[<code>flake8-bugbear</code>] Document type-checker interaction (<code>B010</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28509">#28509</a>)</li> <li>[<code>flake8-comprehensions</code>] Document <code>map</code>/generator exception behavior (<code>C417</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/27794">#27794</a>)</li> <li>[<code>ruff</code>] Mention related isort settings (<code>RUF022</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28719">#28719</a>)</li> </ul> <h3>Contributors</h3> <ul> <li><a href="https://github.com/qinpei-dev"><code>@qinpei-dev</code></a></li> <li><a href="https://github.com/sanjayrohith"><code>@sanjayrohith</code></a></li> <li><a href="https://github.com/ntBre"><code>@ntBre</code></a></li> <li><a href="https://github.com/webdevsamran"><code>@webdevsamran</code></a></li> <li><a href="https://github.com/zaniebot"><code>@zaniebot</code></a></li> <li><a href="https://github.com/ewdurbin"><code>@ewdurbin</code></a></li> <li><a href="https://github.com/MichaReiser"><code>@MichaReiser</code></a></li> <li><a href="https://github.com/spaceone"><code>@spaceone</code></a></li> <li><a href="https://github.com/IbrahimKhan12"><code>@IbrahimKhan12</code></a></li> <li><a href="https://github.com/devtechedge"><code>@devtechedge</code></a></li> <li><a href="https://github.com/GruffElixir"><code>@GruffElixir</code></a></li> </ul> <h2>Install ruff 0.16.9</h2> <h3>Install prebuilt binaries via shell script</h3> <pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf https://releases.astral.sh/github/ruff/releases/download/0.16.9/ruff-installer.sh | sh </code></pre> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's changelog</a>.</em></p> <blockquote> <h2>0.16.9</h2> <p>Released on 2026-09-24.</p> <h3>Preview features</h3> <ul> <li>[<code>ruff</code>] Avoid false positives for overloaded division (<code>RUF069</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28309">#28309</a>)</li> </ul> <h3>Bug fixes</h3> <ul> <li>[<code>flake8-bugbear</code>] Avoid false positives for calls with keyword arguments (<code>B009</code>, <code>B010</code>, <code>B043</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28776">#28776</a>)</li> <li>[<code>flake8-tidy-imports</code>] Allow lazy imports to be used in deferred annotations (<code>TID255</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28767">#28767</a>)</li> </ul> <h3>Rule changes</h3> <ul> <li>Update LibCST-based fixes for Python 3.15 (<a href="https://redirect.github.com/astral-sh/ruff/pull/28616">#28616</a>)</li> <li>[<code>flake8-pyi</code>] Mention stubs in the diagnostic message (<code>PYI002</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28542">#28542</a>)</li> </ul> <h3>Documentation</h3> <ul> <li>Fix horizontal overflow on the rules documentation page (<a href="https://redirect.github.com/astral-sh/ruff/pull/28699">#28699</a>)</li> <li>Update rules table with category information (<a href="https://redirect.github.com/astral-sh/ruff/pull/28651">#28651</a>)</li> <li>[<code>flake8-annotations</code>] Clarify that <code>ANN401</code> checks return types in addition to arguments (<a href="https://redirect.github.com/astral-sh/ruff/pull/28334">#28334</a>)</li> <li>[<code>flake8-bugbear</code>] Document type-checker interaction (<code>B010</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28509">#28509</a>)</li> <li>[<code>flake8-comprehensions</code>] Document <code>map</code>/generator exception behavior (<code>C417</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/27794">#27794</a>)</li> <li>[<code>ruff</code>] Mention related isort settings (<code>RUF022</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28719">#28719</a>)</li> </ul> <h3>Contributors</h3> <ul> <li><a href="https://github.com/qinpei-dev"><code>@qinpei-dev</code></a></li> <li><a href="https://github.com/sanjayrohith"><code>@sanjayrohith</code></a></li> <li><a href="https://github.com/ntBre"><code>@ntBre</code></a></li> <li><a href="https://github.com/webdevsamran"><code>@webdevsamran</code></a></li> <li><a href="https://github.com/zaniebot"><code>@zaniebot</code></a></li> <li><a href="https://github.com/ewdurbin"><code>@ewdurbin</code></a></li> <li><a href="https://github.com/MichaReiser"><code>@MichaReiser</code></a></li> <li><a href="https://github.com/spaceone"><code>@spaceone</code></a></li> <li><a href="https://github.com/IbrahimKhan12"><code>@IbrahimKhan12</code></a></li> <li><a href="https://github.com/devtechedge"><code>@devtechedge</code></a></li> <li><a href="https://github.com/GruffElixir"><code>@GruffElixir</code></a></li> </ul> <h2>0.16.8</h2> <p>Released on 2026-09-16.</p> <h3>Bug fixes</h3> <ul> <li>Visit functional <code>TypedDict</code> keyword arguments correctly (<a href="https://redirect.github.com/astral-sh/ruff/pull/28584">#28584</a>)</li> <li>[<code>flake8-simplify</code>] Detect nested <code>async with</code> under sync parent (<code>SIM117</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/27821">#27821</a>)</li> <li>[<code>flake8-simplify</code>] Preserve operand order in <code>SIM109</code> fix (<a href="https://redirect.github.com/astral-sh/ruff/pull/27824">#27824</a>)</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/astral-sh/ruff/commit/0be08a206f9c3180afd3e93bcc792ed5cb1f4db1"><code>0be08a2</code></a> Bump version to 0.16.9 (<a href="https://redirect.github.com/astral-sh/ruff/issues/28882">#28882</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/b4920b72b354e7c715ab861ae23458874683bb02"><code>b4920b7</code></a> Rename <code>ruff_cli</code> to <code>ruff_command_line</code> (<a href="https://redirect.github.com/astral-sh/ruff/issues/28881">#28881</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/47c751b95908a4d1f95f9ef8723036aae9da0b18"><code>47c751b</code></a> Update dependency astral-sh/uv to v0.12.18 (<a href="https://redirect.github.com/astral-sh/ruff/issues/28880">#28880</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/8c244e56a1aeac31c26d2371ef26588e0632235c"><code>8c244e5</code></a> [<code>flake8-comprehensions</code>] Document <code>map</code>/generator exception behavior (<code>C417</code>...</li> <li><a href="https://github.com/astral-sh/ruff/commit/5edf5a1d0a84663079e46983216059f06acea87d"><code>5edf5a1</code></a> Use <code>target</code> form in <code>rooster.version_files</code> (<a href="https://redirect.github.com/astral-sh/ruff/issues/28876">#28876</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/915bb2b4bf9ae7eee47cf55646bbfebae254a23b"><code>915bb2b</code></a> [ty] Prefer existing @ paths over response files in Ruff and ty (<a href="https://redirect.github.com/astral-sh/ruff/issues/28877">#28877</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/4710e1aa962b13720cf64aa84eb279c5333896d7"><code>4710e1a</code></a> ci(github): update version number in placeholder of issue template (<a href="https://redirect.github.com/astral-sh/ruff/issues/28871">#28871</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/eedfc62a75bf1ba86d48959b00eea75ae87eadca"><code>eedfc62</code></a> [ty] Propagate outer type context through cast calls (<a href="https://redirect.github.com/astral-sh/ruff/issues/28855">#28855</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/ceaa6a00830e1e350b8a23977a1a10ac467920a1"><code>ceaa6a0</code></a> [ty] Contain rendered code within Markdown fences (<a href="https://redirect.github.com/astral-sh/ruff/issues/28869">#28869</a>)</li> <li><a href="https://github.com/astral-sh/ruff/commit/dba0f30615424b94f94a174bba6ce6cce4bf11ff"><code>dba0f30</code></a> authorize ruff-pre-commit dispatch via OIDC (<a href="https://redirect.github.com/astral-sh/ruff/issues/28867">#28867</a>)</li> <li>Additional commits viewable in <a href="https://github.com/astral-sh/ruff/compare/0.16.5...0.16.9">compare view</a></li> </ul> </details> <br /> Updates `ty` from 0.0.75 to 0.0.84 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/astral-sh/ty/releases">ty's releases</a>.</em></p> <blockquote> <h2>0.0.84</h2> <h2>Release Notes</h2> <p>Released on 2026-09-24.</p> <p>This release addresses <a href="https://github.com/astral-sh/ty/security/advisories/GHSA-vxvm-j4xq-q7m4">GHSA-vxvm-j4xq-q7m4</a>, a use-after-free vulnerability during incremental type checking that can result in arbitrary code execution when analyzing a specially crafted Python project. Users who run ty on untrusted code should upgrade to 0.0.84 or newer.</p> <h3>Bug fixes</h3> <ul> <li>Fix stale diagnostics from the LSP server after toggling <code>showSyntaxErrors</code> (<a href="https://redirect.github.com/astral-sh/ruff/pull/28759">#28759</a>)</li> </ul> <h3>LSP server</h3> <ul> <li>Complete string keys from dictionary initializers (<a href="https://redirect.github.com/astral-sh/ruff/pull/28820">#28820</a>)</li> <li>Support LSP requests against closed documents (<a href="https://redirect.github.com/astral-sh/ruff/pull/28595">#28595</a>)</li> <li>Select projects for external files using import search paths (<a href="https://redirect.github.com/astral-sh/ruff/pull/28594">#28594</a>)</li> <li>Use workspace editor settings for external files (<a href="https://redirect.github.com/astral-sh/ruff/pull/28639">#28639</a>)</li> </ul> <h3>Performance</h3> <ul> <li>Avoid repeated subtyping checks for materialized recursive protocols (<a href="https://redirect.github.com/astral-sh/ruff/pull/28774">#28774</a>)</li> <li>Skip reading notebooks when discovering scripts (<a href="https://redirect.github.com/astral-sh/ruff/pull/28781">#28781</a>)</li> </ul> <h3>Core type checking</h3> <ul> <li>Avoid incorrect simplification of <code>TypeIs</code> materializations (<a href="https://redirect.github.com/astral-sh/ruff/pull/28817">#28817</a>)</li> <li>Fix disjointness of generic class types (<a href="https://redirect.github.com/astral-sh/ruff/pull/28787">#28787</a>)</li> <li>Fix staticmethod shadowing through generic receivers and unions (<a href="https://redirect.github.com/astral-sh/ruff/pull/28766">#28766</a>)</li> <li>Infer callable signatures from bounded type variables (<a href="https://redirect.github.com/astral-sh/ruff/pull/28599">#28599</a>)</li> <li>Infer constant membership in inline list and set literals (e.g. <code>"foo" in ["foo"]</code> is now inferred as <code>Literal[True]</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28676">#28676</a>)</li> <li>Infer through optional generic containers in the legacy solver (<a href="https://redirect.github.com/astral-sh/ruff/pull/28791">#28791</a>)</li> <li>Preserve call narrowing during cyclic inference (<a href="https://redirect.github.com/astral-sh/ruff/pull/28708">#28708</a>)</li> <li>Preserve intersections of type guard return types (<a href="https://redirect.github.com/astral-sh/ruff/pull/28796">#28796</a>)</li> <li>Use subtyping for constraint-set implication (<a href="https://redirect.github.com/astral-sh/ruff/pull/28657">#28657</a>)</li> </ul> <h3>Configuration</h3> <ul> <li>Disable <code>invalid-legacy-positional-parameter</code> by default (<a href="https://redirect.github.com/astral-sh/ruff/pull/28834">#28834</a>)</li> </ul> <h3>Other changes</h3> <ul> <li>Only consider reachable definitions when determining whether a condition should be exempted from <code>redundant-condition(-strict)</code> due to the condition being defined relative to <code>sys.version_info</code>, <code>sys.platform</code>, <code>os.name</code> or <code>typing.TYPE_CHECKING</code> (<a href="https://redirect.github.com/astral-sh/ruff/pull/28788">#28788</a>)</li> </ul> <h3>Contributors</h3> <ul> <li><a href="https://github.com/ibraheemdev"><code>@ibraheemdev</code></a></li> <li><a href="https://github.com/zsol"><code>@zsol</code></a></li> <li><a href="https://github.com/charliermarsh"><code>@charliermarsh</code></a></li> <li><a href="https://github.com/lerebear"><code>@lerebear</code></a></li> <li><a href="https://github.com/MichaReiser"><code>@MichaReiser</code></a></li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/astral-sh/ty/blob/main/CHANGELOG.md">ty's changelog</a>.</em></p> <blockquote> <h2>0.0.84</h2> <p>Released on 2026-09-24.</p> <p>This release addresses <a href="https://github.com/astral-sh/ty/security/advisories/GHSA-vxvm-j4xq-q7m4">GHSA-vxvm-j4xq-q7m4</a>, a use-after-free vulnerability during incremental type checking that can result in arbitrary code execution when analyzing a specially crafted Python project. Users who run ty on untrusted code should upgrade to 0.0.84 or newer.</p> <h3>Bug fixes</h3> <ul> <li>Fix stale diagnostics from the LSP server after toggling <code>showSyntaxErrors</code> (<a href="https://redirect.github.com/astral-sh/ruff/pull/28759">#28759</a>)</li> </ul> <h3>LSP server</h3> <ul> <li>Complete string keys from dictionary initializers (<a href="https://redirect.github.com/astral-sh/ruff/pull/28820">#28820</a>)</li> <li>Support LSP requests against closed documents (<a href="https://redirect.github.com/astral-sh/ruff/pull/28595">#28595</a>)</li> <li>Select projects for external files using import search paths (<a href="https://redirect.github.com/astral-sh/ruff/pull/28594">#28594</a>)</li> <li>Use workspace editor settings for external files (<a href="https://redirect.github.com/astral-sh/ruff/pull/28639">#28639</a>)</li> </ul> <h3>Performance</h3> <ul> <li>Avoid repeated subtyping checks for materialized recursive protocols (<a href="https://redirect.github.com/astral-sh/ruff/pull/28774">#28774</a>)</li> <li>Skip reading notebooks when discovering scripts (<a href="https://redirect.github.com/astral-sh/ruff/pull/28781">#28781</a>)</li> </ul> <h3>Core type checking</h3> <ul> <li>Avoid incorrect simplification of <code>TypeIs</code> materializations (<a href="https://redirect.github.com/astral-sh/ruff/pull/28817">#28817</a>)</li> <li>Fix disjointness of generic class types (<a href="https://redirect.github.com/astral-sh/ruff/pull/28787">#28787</a>)</li> <li>Fix staticmethod shadowing through generic receivers and unions (<a href="https://redirect.github.com/astral-sh/ruff/pull/28766">#28766</a>)</li> <li>Infer callable signatures from bounded type variables (<a href="https://redirect.github.com/astral-sh/ruff/pull/28599">#28599</a>)</li> <li>Infer constant membership in inline list and set literals (e.g. <code>"foo" in ["foo"]</code> is now inferred as <code>Literal[True]</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/28676">#28676</a>)</li> <li>Infer through optional generic containers in the legacy solver (<a href="https://redirect.github.com/astral-sh/ruff/pull/28791">#28791</a>)</li> <li>Preserve call narrowing during cyclic inference (<a href="https://redirect.github.com/astral-sh/ruff/pull/28708">#28708</a>)</li> <li>Preserve intersections of type guard return types (<a href="https://redirect.github.com/astral-sh/ruff/pull/28796">#28796</a>)</li> <li>Use subtyping for constraint-set implication (<a href="https://redirect.github.com/astral-sh/ruff/pull/28657">#28657</a>)</li> </ul> <h3>Configuration</h3> <ul> <li>Disable <code>invalid-legacy-positional-parameter</code> by default (<a href="https://redirect.github.com/astral-sh/ruff/pull/28834">#28834</a>)</li> </ul> <h3>Other changes</h3> <ul> <li>Only consider reachable definitions when determining whether a condition should be exempted from <code>redundant-condition(-strict)</code> due to the condition being defined relative to <code>sys.version_info</code>, <code>sys.platform</code>, <code>os.name</code> or <code>typing.TYPE_CHECKING</code> (<a href="https://redirect.github.com/astral-sh/ruff/pull/28788">#28788</a>)</li> </ul> <h3>Contributors</h3> <ul> <li><a href="https://github.com/ibraheemdev"><code>@ibraheemdev</code></a></li> <li><a href="https://github.com/zsol"><code>@zsol</code></a></li> <li><a href="https://github.com/charliermarsh"><code>@charliermarsh</code></a></li> <li><a href="https://github.com/lerebear"><code>@lerebear</code></a></li> <li><a href="https://github.com/MichaReiser"><code>@MichaReiser</code></a></li> <li><a href="https://github.com/ewdurbin"><code>@ewdurbin</code></a></li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/astral-sh/ty/commit/8dd9a7f7fa35a18275d82117e6593ba45507065f"><code>8dd9a7f</code></a> Bump version to 0.0.84 (<a href="https://redirect.github.com/astral-sh/ty/issues/4585">#4585</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/d4e4bf90906c7677049bc3a29d1735de7d22052d"><code>d4e4bf9</code></a> publish to astral-sh/versions via OIDC (<a href="https://redirect.github.com/astral-sh/ty/issues/4581">#4581</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/94ce7333abb356b2068dc98d37a68c993da6d09b"><code>94ce733</code></a> use oidc issued token for docs publication (<a href="https://redirect.github.com/astral-sh/ty/issues/4579">#4579</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/901eeaa9cd9ac06f34e85e4f721f76a0dc36e217"><code>901eeaa</code></a> Update prek dependencies (<a href="https://redirect.github.com/astral-sh/ty/issues/4576">#4576</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/09bf0b1b2114a628f3e2296d3d9d28245066c98b"><code>09bf0b1</code></a> Update docker/setup-buildx-action action to v4.3.0 (<a href="https://redirect.github.com/astral-sh/ty/issues/4575">#4575</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/89d6ffe529dd44f64adc0d28f80744b7c7ab217f"><code>89d6ffe</code></a> Update astral-sh/setup-uv action to v10.2.0 (<a href="https://redirect.github.com/astral-sh/ty/issues/4574">#4574</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/9c214798cfcc59069e986876564638fadf32d774"><code>9c21479</code></a> Bump version to 0.0.83 (<a href="https://redirect.github.com/astral-sh/ty/issues/4569">#4569</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/04c69110b391e96310e6892cbed9936c4f31d7aa"><code>04c6911</code></a> Sync the ty security mirror (<a href="https://redirect.github.com/astral-sh/ty/issues/4549">#4549</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/3fa57a25767c619dbeba697c2acfbb8eb291519a"><code>3fa57a2</code></a> Grant the versions workflow repository read access (<a href="https://redirect.github.com/astral-sh/ty/issues/4550">#4550</a>)</li> <li><a href="https://github.com/astral-sh/ty/commit/a15b35389b44db57f718fd4e19e093481747c53e"><code>a15b353</code></a> use scoped token for release workflow (<a href="https://redirect.github.com/astral-sh/ty/issues/4506">#4506</a>)</li> <li>Additional commits viewable in <a href="https://github.com/astral-sh/ty/compare/0.0.75...0.0.84">compare view</a></li> </ul> </details> <br /> Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: John Kennedy <jkennedyvz@users.noreply.github.com> Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com> |