assistant-ui icon indicating copy to clipboard operation
assistant-ui copied to clipboard

Fix LangGraph Chunk Support

Open eladlachmi opened this issue 7 months ago • 21 comments

This PR resolves #1955. It includes the following changes:

  1. Add support for the messages event type in useLangGraphMessages
  2. Fix parsing/concatenation logic in appendLangChainChunk
  3. A bit of type maintenance - consolidated duplicates, added some types for better readability
  4. Setup vitest in the react-langgraph package
  5. 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:

  1. 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)
  2. ~~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~~
  3. ~~Tool call chunking logic most likely suffers from the same issue as text chunks, but same issue as no. 2~~
  4. ~~Two failing tests in assistant-stream. Fix them, add test task to turbo.json, run as part of PR workflow in GitHub, add test report as comment~~

[!IMPORTANT] Enhance useLangGraphMessages with messages event support, improve chunk handling, and add vitest tests.

  • Behavior:
    • Add support for messages event type in useLangGraphMessages.
    • Fix parsing/concatenation logic in appendLangChainChunk to handle string and array content.
  • Types:
    • Introduce LangGraphKnownEventTypes enum and EventType type in types.ts.
    • Modify LangChainMessageChunk and LangChainMessage types to support optional fields.
  • Testing:
    • Setup vitest in react-langgraph package with vitest.config.ts.
    • Add tests in useLangGraphMessages.test.ts to validate chunk processing and message appending logic.
  • Misc:
    • Add test and test:watch scripts to package.json.
    • Minor type maintenance and consolidation in LangGraphMessageAccumulator.ts.

This description was created by Ellipsis for a23cdf2739c8bc0ce60ef2d9e86ec5d3a9157d2d. You can customize this summary. It will automatically update as commits are pushed.

eladlachmi avatar May 21 '25 16:05 eladlachmi

🦋 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

changeset-bot[bot] avatar May 21 '25 16:05 changeset-bot[bot]

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

vercel[bot] avatar May 21 '25 16:05 vercel[bot]

Someone is attempting to deploy a commit to the assistant-ui Team on Vercel.

A member of the Team first needs to authorize it.

vercel[bot] avatar May 21 '25 16:05 vercel[bot]

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

promptless[bot] avatar May 21 '25 16:05 promptless[bot]

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.yaml is 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.

❤️ Share
🪧 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 @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in 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 pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file 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.

coderabbitai[bot] avatar May 21 '25 16:05 coderabbitai[bot]

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.

jazzberry-ai[bot] avatar May 22 '25 11:05 jazzberry-ai[bot]

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.

jazzberry-ai[bot] avatar May 22 '25 13:05 jazzberry-ai[bot]

@eladlachmi Your help is appreciated, thanks for the PR and bug reports!

  1. 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!

  1. 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
  2. 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

  1. Two failing tests in assistant-stream. Fix them, add test task to turbo.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

AVGVSTVS96 avatar May 23 '25 21:05 AVGVSTVS96

An error occured.

This error may be due to rate limits. If this error persists, please email us.

jazzberry-ai[bot] avatar May 25 '25 11:05 jazzberry-ai[bot]

@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 :)

eladlachmi avatar May 25 '25 12:05 eladlachmi

Bug Report

Name: Incorrect Text Chunk Merging in appendLangChainChunk Severity: Medium Example test case:

  1. Initialize newContent with an image URL: [{type: "image_url", image_url: "url"}]
  2. Call appendLangChainChunk with curr.content as [{type: "text", text: "Hello"}, {type: "text", text: " World"}]
  3. Verify that newContent becomes [{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: The appendLangChainChunk function incorrectly merges consecutive text chunks when curr.content is an array and the last element of newContent is not a text node. It also does not merge consecutive text nodes within curr.content correctly. This can lead to unexpected content structure with multiple text nodes instead of a single combined one.

Comments? Email us.

jazzberry-ai[bot] avatar May 25 '25 13:05 jazzberry-ai[bot]

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.

eladlachmi avatar May 25 '25 13:05 eladlachmi

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.

jazzberry-ai[bot] avatar May 25 '25 13:05 jazzberry-ai[bot]

Bug Report

Name: Incorrect Text Chunk Merging in appendLangChainChunk Severity: Medium Example test case:

  1. Initialize newContent with an image URL: [{type: "image_url", image_url: "url"}]
  2. Call appendLangChainChunk with curr.content as [{type: "text", text: "Hello"}, {type: "text", text: " World"}]
  3. Verify that newContent becomes [{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: The appendLangChainChunk function incorrectly merges consecutive text chunks when curr.content is an array and the last element of newContent is not a text node. It also does not merge consecutive text nodes within curr.content correctly. 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.

eladlachmi avatar May 25 '25 13:05 eladlachmi

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.

This is by-design. Non-consecutive text chunks should not be merged.

eladlachmi avatar May 25 '25 13:05 eladlachmi

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.

jazzberry-ai[bot] avatar May 26 '25 10:05 jazzberry-ai[bot]

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.

jazzberry-ai[bot] avatar May 26 '25 12:05 jazzberry-ai[bot]

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.

jazzberry-ai[bot] avatar May 27 '25 12:05 jazzberry-ai[bot]

@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.

eladlachmi avatar May 28 '25 14:05 eladlachmi

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.

jazzberry-ai[bot] avatar May 28 '25 14:05 jazzberry-ai[bot]

@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

AVGVSTVS96 avatar May 30 '25 21:05 AVGVSTVS96

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.

jazzberry-ai[bot] avatar May 31 '25 18:05 jazzberry-ai[bot]

@trag-bot didn't find any issues in the code! ✅✨

trag-bot[bot] avatar May 31 '25 18:05 trag-bot[bot]