fix(react): backport throttled chat snapshots to v6 - #18533
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Background
useChatin AI SDK 6 throttles its messages subscription callback, but itsuseSyncExternalStoresnapshot always reads the latestchat.messagesarray. Because streaming replaces that array for every chunk, an unrelated React render can observe a new snapshot before the throttled callback publishes it. In high-frequency streams this bypassesexperimental_throttle, causes per-chunk renders, and can contribute to the "Maximum update depth exceeded" failures reported in #6166.This is a branch-native backport of #18525 to
release-v6.0.Summary
useChathook and advance it from that hook's throttled subscription callback.readyorerrorbecomes observable, including normal completion and aborts.ready.@ai-sdk/react.Contributor Credit
Manual Verification
Ran
/chat/throttleinexamples/ai-e2e-nextin a real browser. The route streamed 500 chunks (1,000 assistant characters) withexperimental_throttle: 50while a zero-delay timer independently re-rendered the component.The patched v6 run passed with 15 distinct message snapshots in 860ms (maximum expected: 22), across 462 total React renders. All 1,000 assistant characters were visible on the first render where status became
ready, with no Next.js error overlay.Also ran:
pnpm --filter @ai-sdk/react test -- use-chat.ui.test.tsx(60 tests passed)pnpm checkpnpm type-check:fullChecklist
pnpm changesetin the project root)Future Work
This backport intentionally leaves the v6 opt-in default unchanged, so applications must continue to set
experimental_throttleto benefit from paced React publications.For v8, I recommend making a 50ms UI publication cadence the default when
throttleis omitted, withthrottle: 0as the explicit unthrottled opt-out. Stream processing, tool handling, and callbacks should remain immediate; only snapshots exposed to React should be paced. The default should guarantee an immediate leading publication and a terminal flush so final messages andreadystatus stay coherent.This would cap the normal rendering rate at about 20 updates per second and protect applications that do not know they need to opt in today. The tradeoff is up to 50ms of additional visible text latency and an explicit opt-out for applications that intentionally need per-chunk rendering, which makes the behavior change appropriate for a major release.
Related Issues
Backport of #18525.
Addresses the throttled snapshot bypass discussed in #6166. Reports using the default unthrottled behavior remain outside this PR.
Related to cloudflare/agents#2058.