fix(sdk): send checkpoint_id in runs.stream() request body - #2762
Conversation
`RunsStreamPayload` extends `RunsInvokePayload`, which declares
`checkpointId`, but `RunsClient.stream()` never put it on the wire. A call
like
client.runs.stream(threadId, assistantId, { checkpointId })
type-checks and compiles, yet the run starts from the thread's latest state
instead of forking from the requested checkpoint, with no error.
`runs.create()` and `runs.wait()` in the same class already send
`checkpoint_id`, and the server validates /runs/stream with the same
`RunCreate` schema as /runs and /runs/wait, so the field was simply missing
from one of three otherwise identical request bodies.
🦋 Changeset detectedLatest commit: 60fb4b5 The changes in this PR will be included in the next version bump. This PR includes changesets to release 5 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
@langchain/langgraph-checkpoint
@langchain/langgraph-checkpoint-mongodb
@langchain/langgraph-checkpoint-postgres
@langchain/langgraph-checkpoint-redis
@langchain/langgraph-checkpoint-sqlite
@langchain/langgraph-checkpoint-validation
create-langgraph
@langchain/langgraph-api
@langchain/langgraph-cli
@langchain/langgraph
@langchain/langgraph-cua
@langchain/langgraph-supervisor
@langchain/langgraph-swarm
@langchain/langgraph-ui
@langchain/langgraph-sdk
@langchain/angular
@langchain/react
@langchain/svelte
@langchain/vue
commit: |
|
The five red Only one test actually fails, and it is on the
In the same run, Happy to rebase once #2753 lands, if that would help. |
Christian Bromann (christian-bromann)
left a comment
There was a problem hiding this comment.
LGTM 👍
2fab6fd
into
langchain-ai:main
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ `main` is currently in **pre mode** so this branch has prereleases rather than normal releases. If you want to exit prereleases, run `changeset pre exit` on `main`.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ # Releases ## @langchain/langgraph-api@1.4.6-rc.0 ### Patch Changes - [#2751](#2751) [`0a9611a`](0a9611a) Thanks [@t3s7r](https://github.com/t3s7r)! - fix(api): `run.start` with input on a cancelled thread no longer folds the input into `Command(resume)`. A cancelled run shares the "interrupted" status with a genuine `interrupt()` pause, but has no pending interrupt to consume the resume value, so the submitted message was silently dropped. The input-vs-resume decision now keys on whether the thread actually has pending interrupts (both in the protocol service and the embed protocol). - Updated dependencies [[`83a4b62`](83a4b62), [`2fab6fd`](2fab6fd)]: - @langchain/langgraph@1.4.15-rc.0 - @langchain/langgraph-sdk@1.10.3-rc.0 - @langchain/langgraph-ui@1.4.6-rc.0 ## @langchain/langgraph-cli@1.4.6-rc.0 ### Patch Changes - Updated dependencies [[`0a9611a`](0a9611a)]: - @langchain/langgraph-api@1.4.6-rc.0 ## @langchain/langgraph@1.4.15-rc.0 ### Patch Changes - [#2794](#2794) [`83a4b62`](83a4b62) Thanks [@hntrl](https://github.com/hntrl)! - feat(langgraph): add per-node `tracePolicy` input/output processors and `omitPayload` Transform the payloads recorded on a node's own trace run while retaining its span and timing. Processors receive raw values and fall back to the original payload if they throw. Graph state, root runs, and child runs remain unchanged when processors do not mutate their arguments. Matches Python's callback-level behavior: transforms also affect chain events and message streaming, so omitting outputs can suppress messages returned directly by nodes and omitting inputs can affect message deduplication. - Updated dependencies [[`2fab6fd`](2fab6fd)]: - @langchain/langgraph-sdk@1.10.3-rc.0 ## @langchain/langgraph-cua@1.0.3-rc.0 ### Patch Changes - Updated dependencies [[`83a4b62`](83a4b62)]: - @langchain/langgraph@1.4.15-rc.0 ## @langchain/langgraph-supervisor@1.1.2-rc.0 ### Patch Changes - Updated dependencies [[`83a4b62`](83a4b62)]: - @langchain/langgraph@1.4.15-rc.0 ## @langchain/langgraph-swarm@1.0.3-rc.0 ### Patch Changes - Updated dependencies [[`83a4b62`](83a4b62)]: - @langchain/langgraph@1.4.15-rc.0 ## @langchain/langgraph-sdk@1.10.3-rc.0 ### Patch Changes - [#2762](#2762) [`2fab6fd`](2fab6fd) Thanks [@JessYanCoding](https://github.com/JessYanCoding)! - Send `checkpoint_id` in the `runs.stream()` request body, so a `checkpointId` passed to `client.runs.stream()` forks from the requested checkpoint instead of being silently dropped. Matches `runs.create()` and `runs.wait()`, which already send it. ## @langchain/angular@1.0.36-rc.0 ### Patch Changes - Updated dependencies [[`2fab6fd`](2fab6fd)]: - @langchain/langgraph-sdk@1.10.3-rc.0 ## @langchain/react@1.0.36-rc.0 ### Patch Changes - Updated dependencies [[`2fab6fd`](2fab6fd)]: - @langchain/langgraph-sdk@1.10.3-rc.0 ## @langchain/svelte@1.0.36-rc.0 ### Patch Changes - Updated dependencies [[`2fab6fd`](2fab6fd)]: - @langchain/langgraph-sdk@1.10.3-rc.0 ## @langchain/vue@1.0.36-rc.0 ### Patch Changes - Updated dependencies [[`2fab6fd`](2fab6fd)]: - @langchain/langgraph-sdk@1.10.3-rc.0 ## @langchain/langgraph-ui@1.4.6-rc.0 No changes in this release. --------- Signed-off-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Hunter Lovell <hunter@hntrl.io> Co-authored-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com>
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @langchain/langgraph-sdk@1.11.0 ### Minor Changes - [#2831](#2831) [`3234c69`](3234c69) Thanks [@ramon-langchain](https://github.com/ramon-langchain)! - Expose connection lifecycle callbacks for built-in streaming transports. `onConnected` runs after the initial SSE or WebSocket connection becomes usable and after every successful reconnect. Its payload distinguishes an `initial` connection from a `reconnected` connection and includes the reconnect attempt number. `onReconnect` now also receives the scheduled `delayMs`, allowing applications to display accurate retry state before the next connection attempt. React, Vue, Svelte, and Angular stream hooks forward both callbacks. ### Patch Changes - [#2831](#2831) [`3234c69`](3234c69) Thanks [@ramon-langchain](https://github.com/ramon-langchain)! - Recover cleanly when a thread's root event stream terminates unexpectedly. If the stream fails or closes while a run is active, the controller now records the transport error and clears `isLoading` rather than leaving the UI in a permanently running state. Once the failed pump settles, a later submission can start a fresh root subscription without recreating the thread stream or replaying the failed command. - [#2809](#2809) [`11a4535`](11a4535) Thanks [@hntrl](https://github.com/hntrl)! - fix(sdk): appropriately track persisted seq for stream replay Sequences weren't being appropriately attributed when rehydrating the page (e.g. on refresh). This meant we'd lose stream information on `useStream` on reloads. This has been fixed by adding a lookup step to determine what the most appropriate sequence index is to track in the event stream.:x - [#2762](#2762) [`2fab6fd`](2fab6fd) Thanks [@JessYanCoding](https://github.com/JessYanCoding)! - Send `checkpoint_id` in the `runs.stream()` request body, so a `checkpointId` passed to `client.runs.stream()` forks from the requested checkpoint instead of being silently dropped. Matches `runs.create()` and `runs.wait()`, which already send it. - [#2813](#2813) [`4fc118f`](4fc118f) Thanks [@eliornl](https://github.com/eliornl)! - fix(sdk): show interrupts raised after a passive thread rejoin After a page refresh mid-run, `useStream` filtered every interrupt it did not already know from the hydrated thread state as replayed history, and waited for a `checkpoints` event to lift that filter. Current runtimes never emit that event and the replay buffer trims it on long runs, so interrupts raised after the refresh never appeared until the next reload. Unknown interrupts are now settled against the server's thread state when the run reaches a terminal lifecycle: the ones the server lists as pending are shown, the rest are dropped as history. - [#2812](#2812) [`db4bdad`](db4bdad) Thanks [@eliornl](https://github.com/eliornl)! - fix(sdk): recover from a server-side thread stream drop instead of freezing The protocol SSE transport now reconnects when the server closes the event stream cleanly. The thread stream is open-ended, so a clean close only happens when the server's own upstream consumer died or it is restarting; before, the client treated it as the end of the thread and the UI froze mid-run with no error. A connection that delivered events also resets the reconnect budget, so long-lived pages survive repeated deploys. `maxReconnectAttempts: 0` keeps the old end-on-close behavior. Unsolicited server error frames (no command id) and a shared stream that gives up reconnecting now reach `stream.error`: `ThreadStream.onError` exposes them, `useStream` sets `error`, clears `isLoading`, and settles the in-flight `submit()` as failed. - [#2808](#2808) [`55fa26b`](55fa26b) Thanks [@hntrl](https://github.com/hntrl)! - fix(sdk): coalesce locally resolved interrupts when resolving interrupts using `useStream`, there was a case where we prioritized the remote state values (which we lookup in React Strict mode on every page transition) over the local interrupt responses we know we've responded with. This has since been fixed to first prioritize the local cache of interrupts, resolved against the remote state values when a run hits a terminal event ## @langchain/angular@1.1.0 ### Minor Changes - [#2831](#2831) [`3234c69`](3234c69) Thanks [@ramon-langchain](https://github.com/ramon-langchain)! - Expose connection lifecycle callbacks for built-in streaming transports. `onConnected` runs after the initial SSE or WebSocket connection becomes usable and after every successful reconnect. Its payload distinguishes an `initial` connection from a `reconnected` connection and includes the reconnect attempt number. `onReconnect` now also receives the scheduled `delayMs`, allowing applications to display accurate retry state before the next connection attempt. React, Vue, Svelte, and Angular stream hooks forward both callbacks. ### Patch Changes - Updated dependencies [[`3234c69`](3234c69), [`3234c69`](3234c69), [`11a4535`](11a4535), [`2fab6fd`](2fab6fd), [`4fc118f`](4fc118f), [`db4bdad`](db4bdad), [`55fa26b`](55fa26b)]: - @langchain/langgraph-sdk@1.11.0 ## @langchain/react@1.1.0 ### Minor Changes - [#2831](#2831) [`3234c69`](3234c69) Thanks [@ramon-langchain](https://github.com/ramon-langchain)! - Expose connection lifecycle callbacks for built-in streaming transports. `onConnected` runs after the initial SSE or WebSocket connection becomes usable and after every successful reconnect. Its payload distinguishes an `initial` connection from a `reconnected` connection and includes the reconnect attempt number. `onReconnect` now also receives the scheduled `delayMs`, allowing applications to display accurate retry state before the next connection attempt. React, Vue, Svelte, and Angular stream hooks forward both callbacks. ### Patch Changes - Updated dependencies [[`3234c69`](3234c69), [`3234c69`](3234c69), [`11a4535`](11a4535), [`2fab6fd`](2fab6fd), [`4fc118f`](4fc118f), [`db4bdad`](db4bdad), [`55fa26b`](55fa26b)]: - @langchain/langgraph-sdk@1.11.0 ## @langchain/svelte@1.1.0 ### Minor Changes - [#2831](#2831) [`3234c69`](3234c69) Thanks [@ramon-langchain](https://github.com/ramon-langchain)! - Expose connection lifecycle callbacks for built-in streaming transports. `onConnected` runs after the initial SSE or WebSocket connection becomes usable and after every successful reconnect. Its payload distinguishes an `initial` connection from a `reconnected` connection and includes the reconnect attempt number. `onReconnect` now also receives the scheduled `delayMs`, allowing applications to display accurate retry state before the next connection attempt. React, Vue, Svelte, and Angular stream hooks forward both callbacks. ### Patch Changes - Updated dependencies [[`3234c69`](3234c69), [`3234c69`](3234c69), [`11a4535`](11a4535), [`2fab6fd`](2fab6fd), [`4fc118f`](4fc118f), [`db4bdad`](db4bdad), [`55fa26b`](55fa26b)]: - @langchain/langgraph-sdk@1.11.0 ## @langchain/vue@1.1.0 ### Minor Changes - [#2831](#2831) [`3234c69`](3234c69) Thanks [@ramon-langchain](https://github.com/ramon-langchain)! - Expose connection lifecycle callbacks for built-in streaming transports. `onConnected` runs after the initial SSE or WebSocket connection becomes usable and after every successful reconnect. Its payload distinguishes an `initial` connection from a `reconnected` connection and includes the reconnect attempt number. `onReconnect` now also receives the scheduled `delayMs`, allowing applications to display accurate retry state before the next connection attempt. React, Vue, Svelte, and Angular stream hooks forward both callbacks. ### Patch Changes - Updated dependencies [[`3234c69`](3234c69), [`3234c69`](3234c69), [`11a4535`](11a4535), [`2fab6fd`](2fab6fd), [`4fc118f`](4fc118f), [`db4bdad`](db4bdad), [`55fa26b`](55fa26b)]: - @langchain/langgraph-sdk@1.11.0 ## @langchain/langgraph-api@1.4.6 ### Patch Changes - [#2751](#2751) [`0a9611a`](0a9611a) Thanks [@t3s7r](https://github.com/t3s7r)! - fix(api): `run.start` with input on a cancelled thread no longer folds the input into `Command(resume)`. A cancelled run shares the "interrupted" status with a genuine `interrupt()` pause, but has no pending interrupt to consume the resume value, so the submitted message was silently dropped. The input-vs-resume decision now keys on whether the thread actually has pending interrupts (both in the protocol service and the embed protocol). - Updated dependencies []: - @langchain/langgraph-ui@1.4.6 ## @langchain/langgraph-cli@1.4.6 ### Patch Changes - Updated dependencies [[`0a9611a`](0a9611a)]: - @langchain/langgraph-api@1.4.6 ## @langchain/langgraph@1.4.15 ### Patch Changes - [#2794](#2794) [`83a4b62`](83a4b62) Thanks [@hntrl](https://github.com/hntrl)! - feat(langgraph): add per-node `tracePolicy` input/output processors and `omitPayload` Transform the payloads recorded on a node's own trace run while retaining its span and timing. Processors receive raw values and fall back to the original payload if they throw. Graph state, root runs, and child runs remain unchanged when processors do not mutate their arguments. Matches Python's callback-level behavior: transforms also affect chain events and message streaming, so omitting outputs can suppress messages returned directly by nodes and omitting inputs can affect message deduplication. - Updated dependencies [[`3234c69`](3234c69), [`3234c69`](3234c69), [`11a4535`](11a4535), [`2fab6fd`](2fab6fd), [`4fc118f`](4fc118f), [`db4bdad`](db4bdad), [`55fa26b`](55fa26b)]: - @langchain/langgraph-sdk@1.11.0 ## @langchain/langgraph-cua@1.0.3 No changes in this release. ## @langchain/langgraph-supervisor@1.1.2 No changes in this release. ## @langchain/langgraph-swarm@1.0.3 No changes in this release. ## @langchain/langgraph-ui@1.4.6 No changes in this release. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Summary
RunsStreamPayloadextendsRunsInvokePayload(libs/sdk/src/types.ts:171,:48), which declarescheckpointId— "Checkpoint ID for when creating a new run" (types.ts:70-73). ButRunsClient.stream()builds its wire body atruns/index.ts:79-101and includescheckpointwhile omittingcheckpoint_id.So this type-checks, compiles, and silently runs from the thread's latest state instead of forking from the requested checkpoint:
No error is raised, and the caller gets no signal that the checkpoint was ignored.
Reproduction
The same
checkpointIdpassed to all three methods on a realClient, with a stubcallerOptions.fetchcapturing the outgoing request body:checkpoint_idin body — before/threads/t1/runs/stream/threads/t1/runs/threads/t1/runs/waitWhy this looks like a plain omission rather than intent
RunsClient.create()(runs/index.ts:151) andRunsClient.wait()(:240) in the same class both sendcheckpoint_id./runs/streamwith the sameschemas.RunCreateas/runsand/runs/wait—libs/langgraph-api/src/api/runs.mts:181, 257, 268, 342, 383.The field was simply missing from one of three otherwise identical bodies.
The change
One line, placed exactly where
create()has it (immediately aftercheckpoint):Tests
Added
sends checkpointId as checkpoint_id in the request bodyto the existingdescribe("runs.stream()")block insrc/client/runs/stream.test.ts, next to the existing body-shape assertions and reusing that file's SSE harness.Reverse-verified: with the one-line change reverted, the new test fails (
expected undefined to be '1f0aaaaa-…'). With it applied,pnpm testinlibs/sdkgives 53 files / 779 tests passing, no type errors;pnpm lintandpnpm format:checkare clean at the repo root.A changeset is included (
@langchain/langgraph-sdk: patch).Note
stream()also omitslangsmith_tracer, whichcreate()andwait()both send. I left it out to keep this change to a single field — happy to include it here or open a follow-up, whichever you prefer.This contribution was prepared with AI assistance.