Skip to content

revert(sdk): appropriately track persisted seq for stream replay (#2807) - #2814

Merged
Hunter Lovell (hntrl) merged 1 commit into
mainfrom
hunter/revert-2807
Sep 9, 2026
Merged

Hunter Lovell (hntrl) merged 1 commit into
mainfrom
hunter/revert-2807

Conversation

@hntrl

Copy link
Copy Markdown
Member

This reverts commit dfa4332.

@changeset-bot

changeset-bot Bot commented Sep 9, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 10ae5ac

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@hntrl Hunter Lovell (hntrl) changed the title Revert "fix(sdk): appropriately track persisted seq for stream replay (#2807)" revert(sdk): appropriately track persisted seq for stream replay (#2807) Sep 9, 2026

@open-swe open-swe Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open SWE Review found 1 potential issue.

Open in WebView Open SWE trace

Comment thread libs/sdk/src/stream/controller.ts
@pkg-pr-new

pkg-pr-new Bot commented Sep 9, 2026

Copy link
Copy Markdown

Open in StackBlitz

@langchain/langgraph-checkpoint

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-checkpoint@2814

@langchain/langgraph-checkpoint-mongodb

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-checkpoint-mongodb@2814

@langchain/langgraph-checkpoint-postgres

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-checkpoint-postgres@2814

@langchain/langgraph-checkpoint-redis

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-checkpoint-redis@2814

@langchain/langgraph-checkpoint-sqlite

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-checkpoint-sqlite@2814

@langchain/langgraph-checkpoint-validation

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-checkpoint-validation@2814

create-langgraph

npm i https://pkg.pr.new/langchain-ai/langgraphjs/create-langgraph@2814

@langchain/langgraph-api

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-api@2814

@langchain/langgraph-cli

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-cli@2814

@langchain/langgraph

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph@2814

@langchain/langgraph-cua

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-cua@2814

@langchain/langgraph-supervisor

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-supervisor@2814

@langchain/langgraph-swarm

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-swarm@2814

@langchain/langgraph-ui

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-ui@2814

@langchain/langgraph-sdk

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-sdk@2814

@langchain/angular

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/angular@2814

@langchain/react

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/react@2814

@langchain/svelte

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/svelte@2814

@langchain/vue

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/vue@2814

commit: 10ae5ac

@hntrl
Hunter Lovell (hntrl) merged commit c5f2658 into main Sep 9, 2026
29 of 30 checks passed
@hntrl
Hunter Lovell (hntrl) deleted the hunter/revert-2807 branch September 9, 2026 17:19
Elior Nataf Lackritz (eliornl) added a commit that referenced this pull request Sep 9, 2026
## Summary

Fixes LG-661. After a page refresh (or a second tab) while a run is in
progress, an interrupt the run then raises never shows up in `useStream`
until the next reload. `isLoading` still drops to false, so the agent
looks stuck. Reproduced on a real server with a slow-then-interrupt
graph: the original tab shows the interrupt, the refreshed tab shows
`interrupts: []`.

## Why it happens

After hydrate, the controller treats every `input.requested` it does not
already know from `state.tasks[].interrupts` as replayed history,
because the SSE replays the whole thread buffer on connect and the
stream has no marker for where replay ends. #2807 parks those unknown
interrupts until a `checkpoints` event carrying the hydrated checkpoint
id arrives, then releases everything newer.

That event never arrives:

- LangGraph Python emits the `checkpoints` stream mode as a
`get_state()`-shaped snapshot. The server session only forwards a
checkpoint envelope with a top-level string `id`, so nothing is
forwarded. Zero `checkpoints` events on the wire in the reproduction,
matching the customer's HAR.
- LangGraph.js has no `checkpoints` emission at all
(`libs/langgraph/src`).
- The Redis replay buffer trims by age (120s), so on a long node the
matching event is gone before the refresh even when it did exist.

So the parked interrupts wait forever.

## The fix

Decide parked interrupts with the server's thread state instead of a
stream marker.

- Unknown interrupts are parked as before, now whether or not hydrate
returned a checkpoint id (the release no longer needs it).
- When a root terminal lifecycle (`interrupted` / `completed` /
`failed`) arrives with interrupts parked, `#settleParkedInterrupts` runs
the existing `#reconcilePendingInterruptsFromServer`: ids the server
lists as pending are shown, the rest are dropped as history. Payloads
come from `state.tasks[].interrupts`, the same source hydrate uses, so a
refreshed tab and a fresh load agree by construction.
- The server commits the interrupt to thread state slightly after it
streams the event (the server has its own 5s settle poll for this), so
the fetch retries every 500ms for up to 5s. One loop runs at a time, so
a replay burst with many old terminals costs one loop, not one per
event. The common path (no parked interrupts) makes no extra calls.
- Rebased on #2814, which reverts the `checkpoints` barrier from #2807.
This PR carries the parking list itself; the barrier is gone, so the
settle against server state is the only release path.

## Tests

`controller.test.ts`:

- shows an interrupt raised after a passive rejoin without a checkpoints
event
- waits for the server to commit the interrupt before showing it (second
fetch returns it)
- drops replayed interrupts the server no longer lists

All three fail on `main`. The two #2807 tests still pass. Full
`libs/sdk` unit suite (794) and `libs/sdk-react` browser suite (244)
pass.

Real-stack check (langgraph-api inmem, langgraph 1.2.6): submit a run,
create a second `StreamController` on the same thread 1s in, let the run
interrupt at 4s. Before: refreshed tab `interrupts: []`. After:
refreshed tab shows the interrupt, `respond()` from that tab resumes the
run, and it completes.

## Follow-ups (not in this PR)

- The `checkpoints` channel is dead on the wire for every current
deployment; the server never forwards it because no runtime produces the
`{id, parent_id, step, source}` envelope.
- `onCompleted` not firing after a refresh (also reported in the
thread): `#runLifecycleListener` requires `isLoading` to be true, and
the buffer's `running` event is trimmed on long runs.

Changeset: `@langchain/langgraph-sdk` patch.

---------

Co-authored-by: Hunter Lovell <hunter@hntrl.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants