Fix LangGraph Chunk Support
This PR resolves #1955. It includes the following changes:
- Add support for the
messagesevent type inuseLangGraphMessages - Fix parsing/concatenation logic in
appendLangChainChunk - A bit of type maintenance - consolidated duplicates, added some types for better readability
- Setup
vitestin thereact-langgraphpackage - Tests to validate the new parsing/concat logic in
useLangGraphMessages
Aside from the tests I've also validated this against one of our agents, which failed to render correctly before.
Edit: TODOs - Things I notice while working on this PR, which I don't think should be part of this PR, but I'd like to open issues for and contribute those features:
- Allow passing of handlers from the top-level for different event types, e.g.,
onMetadataEvent,onInfoEvent,onErrorEvent,onCustomEvent, etc. This way consumers can handle events that aren't handled by the package themselves (with default no-op handlers) - ~~The main use case for my team is streaming text token-by-token. Image chunks are also a thing, but we don't currently have any agents that stream image events. I'll have to set up an agent specifically to figure out the expected structure~~
- ~~Tool call chunking logic most likely suffers from the same issue as text chunks, but same issue as no. 2~~
- ~~Two failing tests in assistant-stream. Fix them, add
testtask toturbo.json, run as part of PR workflow in GitHub, add test report as comment~~
[!IMPORTANT] Enhance
useLangGraphMessageswithmessagesevent support, improve chunk handling, and addvitesttests.
- Behavior:
- Add support for
messagesevent type inuseLangGraphMessages.- Fix parsing/concatenation logic in
appendLangChainChunkto handle string and array content.- Types:
- Introduce
LangGraphKnownEventTypesenum andEventTypetype intypes.ts.- Modify
LangChainMessageChunkandLangChainMessagetypes to support optional fields.- Testing:
- Setup
vitestinreact-langgraphpackage withvitest.config.ts.- Add tests in
useLangGraphMessages.test.tsto validate chunk processing and message appending logic.- Misc:
- Add
testandtest:watchscripts topackage.json.- Minor type maintenance and consolidation in
LangGraphMessageAccumulator.ts.This description was created by
for a23cdf2739c8bc0ce60ef2d9e86ec5d3a9157d2d. You can customize this summary. It will automatically update as commits are pushed.
🦋 Changeset detected
Latest commit: 5bb57c861f7cd16a0306274c73c54724116116eb
The changes in this PR will be included in the next version bump.
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
The latest updates on your projects. Learn more about Vercel for Git ↗︎
| Name | Status | Preview | Comments | Updated (UTC) |
|---|---|---|---|---|
| assistant-ui-registry | ✅ Ready (Inspect) | Visit Preview | 💬 Add feedback | May 22, 2025 1:06pm |
Someone is attempting to deploy a commit to the assistant-ui Team on Vercel.
A member of the Team first needs to authorize it.
Review Summary
Skipped posting 2 drafted comments based on your review threshold. Feel free to update them here.
Draft Comments
packages/react-langgraph/src/appendLangChainChunk.ts:41-42
The code doesn't properly handle the case when `curr.content` is an empty array. This could lead to unexpected behavior when processing chunks with empty content arrays.
Scores:
- Production Impact: 4
- Fix Specificity: 5
- Urgency Impact: 4
- Total Score: 13
Reason for filtering: The comment addresses a valid correctness issue with handling empty arrays that doesn't violate any of the user's strict rules
Analysis: The code review identifies a potential bug when handling empty content arrays. The suggested fix is specific and directly applicable. This issue could cause unexpected behavior in production when processing chunks with empty content arrays. The fix is straightforward and doesn't conflict with any of the user's strict rules about code style or implementation preferences.
packages/react-langgraph/src/useLangGraphMessages.test.ts:121-121
There's a typo in the test message content: `How my I assist you today?` should be `How may I assist you today?`. This typo appears in multiple test cases.
Scores:
- Production Impact: 1
- Fix Specificity: 5
- Urgency Impact: 2
- Total Score: 8
Reason for filtering: The comment identifies a typo in test message content that should be fixed for correctness
Analysis: This comment identifies a simple typo in test code ('my' instead of 'may'). The fix is very specific and clear. However, since this is in test code, not production code, the production impact is minimal. The urgency is low as this typo doesn't affect test functionality. With a total score of 8, which is below the threshold of 13, this comment should be removed.
📝 Documentation updates detected!
New suggestion: Update LangGraph documentation for messages event type support
Walkthrough
This update enhances the @assistant-ui/react-langgraph package by adding testing capabilities with Vitest and React Testing Library, including new test scripts in package.json and a dedicated Vitest configuration file. It introduces a comprehensive test suite for the useLangGraphMessages hook to validate message streaming and accumulation behavior. Type definitions are expanded with exported types, enums for event types, and optional properties to clarify message chunk structures. The hook’s event handling is refactored to use these types and a switch statement for better control flow and type safety. The deprecated LangGraphMessagesEvent type alias is removed. The function for appending message chunks is improved to handle both string and array content robustly. Additionally, the TypeScript base configuration is updated to target ES2023.
📜 Recent review details
Configuration used: CodeRabbit UI Review profile: CHILL Plan: Pro
📥 Commits
Reviewing files that changed from the base of the PR and between 599c5c31977b86ff271c8c2f11c4c8cfb50d7d67 and 7d44e731a559986f30bf6a7986ea9dbf8c6dc809.
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (1)
packages/react-langgraph/package.json(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/react-langgraph/package.json
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
🪧 Tips
Chat
There are 3 ways to chat with CodeRabbit:
- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
I pushed a fix in commit <commit_id>, please review it.Explain this complex logic.Open a follow-up GitHub issue for this discussion.
- Files and specific lines of code (under the "Files changed" tab): Tag
@coderabbitaiin a new review comment at the desired location with your query. Examples:@coderabbitai explain this code block.@coderabbitai modularize this function.
- PR comments: Tag
@coderabbitaiin a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.@coderabbitai read src/utils.ts and explain its main purpose.@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.@coderabbitai help me debug CodeRabbit configuration file.
Support
Need help? Create a ticket on our support page for assistance with any issues or questions.
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.
CodeRabbit Commands (Invoked using PR comments)
@coderabbitai pauseto pause the reviews on a PR.@coderabbitai resumeto resume the paused reviews.@coderabbitai reviewto trigger an incremental review. This is useful when automatic reviews are disabled for the repository.@coderabbitai full reviewto do a full review from scratch and review all the files again.@coderabbitai summaryto regenerate the summary of the PR.@coderabbitai generate docstringsto generate docstrings for this PR.@coderabbitai generate sequence diagramto generate a sequence diagram of the changes in this PR.@coderabbitai resolveresolve all the CodeRabbit review comments.@coderabbitai configurationto show the current CodeRabbit configuration for the repository.@coderabbitai helpto get help.
Other keywords and placeholders
- Add
@coderabbitai ignoreanywhere in the PR description to prevent this PR from being reviewed. - Add
@coderabbitai summaryto generate the high-level summary at a specific location in the PR description. - Add
@coderabbitaianywhere in the PR title to generate the title automatically.
CodeRabbit Configuration File (.coderabbit.yaml)
- You can programmatically configure CodeRabbit by adding a
.coderabbit.yamlfile to the root of your repository. - Please see the configuration documentation for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation:
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
Documentation and Community
- Visit our Documentation for detailed information on how to use CodeRabbit.
- Join our Discord Community to get help, request features, and share feedback.
- Follow us on X/Twitter for updates and announcements.
Bug Report
| Name | Severity | Example test case | Description |
|---|---|---|---|
| sendMessage modifies original messages array | Medium | ```javascript | |
| it("should not modify the original messages array", async () => { |
const mockStreamCallback = mockStreamCallbackFactory([
metadataEvent,
{
event: "messages",
data: [
{
id: "run-1",
content: "",
additional_kwargs: {},
response_metadata: { model_name: "claude-3-7-sonnet-latest" },
type: "AIMessageChunk",
name: null,
tool_calls: [],
invalid_tool_calls: [],
tool_call_chunks: [],
},
{
run_attempt: 1,
},
],
},
]);
const { result } = renderHook(() =>
useLangGraphMessages({
stream: mockStreamCallback,
appendMessage: appendLangChainChunk,
}),
);
const originalMessages = [
{
type: "human",
content: "Hello, world!",
},
] as any[];
const messagesCopy = JSON.parse(JSON.stringify(originalMessages));
act(() => {
result.current.sendMessage(
originalMessages,
{},
);
});
await waitFor(() => {
expect(originalMessages).toEqual(messagesCopy);
});
});
``` | The sendMessage function in useLangGraphMessages.ts modifies the original newMessages array by adding an id property if it doesn't exist. This can lead to unexpected side effects if the caller of sendMessage relies on the original array to remain unchanged. To fix this, create a deep copy of the message object before adding the id property.
Comments? Email us. Your free trial ends in 7 days.
Bug Report
Name: Missing Metadata Handling Severity: Low Example test case: The LangGraph stream emits a "metadata" event, but the useLangGraphMessages hook ignores it. Description: The useLangGraphMessages hook currently doesn't store or expose any metadata from the LangGraph stream. This could limit the hook's usefulness in scenarios where metadata is required for debugging, analytics, or other purposes. The hook should store the metadata in the component's state and provide a way to access it.
Comments? Email us. Your free trial ends in 7 days.
@eladlachmi Your help is appreciated, thanks for the PR and bug reports!
- Allow passing of handlers from the top-level for different event types, e.g.,
onMetadataEvent,onInfoEvent,onErrorEvent,onCustomEvent, etc. This way consumers can handle events that aren't handled by the package themselves (with default no-op handlers)
This would be great!
- The main use case for my team is streaming text token-by-token. Image chunks are also a thing, but we don't currently have any agents that stream image events. I'll have to set up an agent specifically to figure out the expected structure
- Tool call chunking logic most likely suffers from the same issue as text chunks, but same issue as no. 2
Good call, let us know if you have a chance to do some more testing
- Two failing tests in assistant-stream. Fix them, add
testtask toturbo.json, run as part of PR workflow in GitHub, add test report as comment
PR #1915 should fix this but needs to use vitest instead of jest, and needs to add the test task to run in PR workflow, take a look and let me know if you have any other thoughts
An error occured.
This error may be due to rate limits. If this error persists, please email us.
@AVGVSTVS96 I've improved the content chunk merging logic and added tests. I was able to test that image chunks are working.
Regarding tool_call_chunks, I can't produce those with any of our LLM providers, so I have no way of testing them. I have, however, looked over the corresponding logic in LangChain, and it seems like the current implementation should handle them correctly.
Any thoughts on when you'll be able to review and merge this PR? My team is looking forward to this fix :)
Bug Report
Name: Incorrect Text Chunk Merging in appendLangChainChunk Severity: Medium Example test case:
- Initialize
newContentwith an image URL:[{type: "image_url", image_url: "url"}] - Call
appendLangChainChunkwithcurr.contentas[{type: "text", text: "Hello"}, {type: "text", text: " World"}] - Verify that
newContentbecomes[{type: "image_url", image_url: "url"}, {type: "text", text: "Hello"}, {type: "text", text: " World"}]instead of[{type: "image_url", image_url: "url"}, {type: "text", text: "Hello World"}]Description: TheappendLangChainChunkfunction incorrectly merges consecutive text chunks whencurr.contentis an array and the last element ofnewContentis not a text node. It also does not merge consecutive text nodes withincurr.contentcorrectly. This can lead to unexpected content structure with multiple text nodes instead of a single combined one.
Comments? Email us.
Allow passing of handlers from the top-level for different event types, e.g., onMetadataEvent, onInfoEvent, onErrorEvent, onCustomEvent, etc. This way consumers can handle events that aren't handled by the package themselves (with default no-op handlers)
This would be great!
It touches some of the same areas I'm touching in this PR, so to minimize extra work and merge conflicts, I'll implement that once this is merged.
PR #1915 should fix this but needs to use vitest instead of jest, and needs to add the test task to run in PR workflow, take a look and let me know if you have any other thoughts
@AVGVSTVS96 Looks like this PR is unrelated to the failures I reported. main already includes vitest installed in this package, so getting #1915 to a merge-able state might be a challenge. TBH, looking at that PR, I'm not sure there's anything worth merging in there at this point.
Bug Report
| Name | Severity | Example test case | Description |
|---|---|---|---|
| Incorrect merging of text chunks when image chunks are present | Medium | prev.content is [{type: "text", text: "Hello"}], curr.content is [{type: "image_url", image_url: "url1"}, {type: "text", text: " world"}] |
The current implementation of appendLangChainChunk does not correctly merge consecutive text chunks when an image chunk is present between them. This can lead to a broken user experience where text is split into multiple parts. The fix is to update the lastIndex in the loop for image_url as well. |
Comments? Email us.
Bug Report
Name: Incorrect Text Chunk Merging in appendLangChainChunk Severity: Medium Example test case:
- Initialize
newContentwith an image URL:[{type: "image_url", image_url: "url"}]- Call
appendLangChainChunkwithcurr.contentas[{type: "text", text: "Hello"}, {type: "text", text: " World"}]- Verify that
newContentbecomes[{type: "image_url", image_url: "url"}, {type: "text", text: "Hello"}, {type: "text", text: " World"}]instead of[{type: "image_url", image_url: "url"}, {type: "text", text: "Hello World"}]Description: TheappendLangChainChunkfunction incorrectly merges consecutive text chunks whencurr.contentis an array and the last element ofnewContentis not a text node. It also does not merge consecutive text nodes withincurr.contentcorrectly. This can lead to unexpected content structure with multiple text nodes instead of a single combined one.Comments? Email us.
Added a test to prove this bug doesn't actually exist.
Bug Report
Name Severity Example test case Description Incorrect merging of text chunks when image chunks are present Medium
prev.contentis[{type: "text", text: "Hello"}],curr.contentis[{type: "image_url", image_url: "url1"}, {type: "text", text: " world"}]The current implementation ofappendLangChainChunkdoes not correctly merge consecutive text chunks when an image chunk is present between them. This can lead to a broken user experience where text is split into multiple parts. The fix is to update the lastIndex in the loop for image_url as well. Comments? Email us.
This is by-design. Non-consecutive text chunks should not be merged.
Bug Report
| Name | Severity | Example test case | Description |
|---|---|---|---|
| Missing content types in appendLangChainChunk | Medium | Add a content part with type 'unknown' to a message. | The appendLangChainChunk function discards content parts with types other than 'text' or 'image_url', leading to data loss. |
Comments? Email us.
Bug Report
| Name | Severity | Example test case | Description |
|---|---|---|---|
| Consecutive Image Chunks | Low | Receive two consecutive image_url chunks | The code adds consecutive image_url chunks to the content array without merging them. While not a bug, this could lead to suboptimal rendering. |
| Mixed Content Chunk Handling | Low | Receive a single chunk containing a mix of text and image content | The code adds the mixed content to the end of the content array without merging possible adjacent text nodes. |
Comments? Email us.
Bug Report
| Name | Severity | Example test case | Description |
|---|---|---|---|
| Null content in appendLangChainChunk | Low | Send a LangChainMessageChunk with content: null | The appendLangChainChunk function doesn't explicitly handle null values for curr.content, potentially leading to unexpected behavior. Although isLangChainMessageChunk in useLangGraphMessages.ts checks for undefined content, it doesn't prevent null content from reaching appendLangChainChunk.ts. |
Comments? Email us.
@Yonom @AVGVSTVS96 Hi 👋🏻 Just wanted to follow up on this PR—let me know if there’s anything you'd like me to change or clarify. My team and I are really looking forward to having this fix in a published release, as it’s currently blocking part of our workflow. Totally understand things can get busy, and I really appreciate all the work you’re doing 🙏🏻 Happy to help move this along however I can.
Bug Report
| Name | Severity | Example test case | Description |
|---|---|---|---|
| Incorrect Tool Call Merging | Medium | Receive tool call chunks with non-sequential or non-1-based index values. | The appendLangChainChunk function assumes that tool call chunk indices are sequential and start from 1. If the indices are non-sequential or start from a different number, this could lead to incorrect tool call merging or out-of-bounds access in the newToolCalls array. |
Comments? Email us.
@Yonom @AVGVSTVS96 Hi 👋🏻 Just wanted to follow up on this PR—let me know if there’s anything you'd like me to change or clarify. My team and I are really looking forward to having this fix in a published release, as it’s currently blocking part of our workflow. Totally understand things can get busy, and I really appreciate all the work you’re doing 🙏🏻 Happy to help move this along however I can.
Thanks for your work on this! Will review and get back to you shortly
Bug Report
| Name | Severity | Example test case | Description |
|---|---|---|---|
| Incorrect Chunk Merging with Image URLs | Medium | A message with existing text and an image URL receives a new text chunk. | The new text is incorrectly prepended to the image URL instead of being appended after it. |
Comments? Email us.
@trag-bot didn't find any issues in the code! ✅✨