Commit graph

6 commits

Author SHA1 Message Date
Danny Avila
b4d97bd888
🗜️ refactor: Eliminate Unstable React Keys During SSE Lifecycle (#12536)
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
* debug: add instrumentation to MessageIcon arePropsEqual + render cycle tests

Temporary debug commit to identify which field triggers MessageIcon
re-renders during message creation and streaming.

arePropsEqual now logs 'icon_memo_diff' with the exact field name and
prev/next values whenever it returns false. Filter browser console for
'icon_memo_diff' to see the trigger.

Also adds render-level integration tests that simulate the message
lifecycle (initial mount, streaming chunks, context updates) and
assert render counts via logger spy.

* perf: stabilize MultiMessage key to prevent unmount/remount during SSE lifecycle

messageId changes 3 times during the SSE message lifecycle:
1. useChatFunctions creates initialResponse with client-generated UUID
2. createdHandler replaces it with userMessageId + '_'
3. finalHandler replaces it with server-assigned messageId

Since MultiMessage used key={message.messageId}, each change caused
React to destroy and recreate the entire message component subtree,
unmounting MessageIcon and all memoized children. This produced visible
icon/image flickering that no memo comparator could prevent.

Switch to key={parentMessageId + '_' + siblingIdx}:
- parentMessageId is stable from creation through final response
- siblingIdx ensures sibling switches still get clean remounts
- Eliminates 2 unnecessary unmount/remount cycles per message

Add key stability tests verifying:
- Current key={messageId} causes 3 mounts / 2 unmounts per lifecycle
- Stable key causes 1 mount / 0 unmounts per lifecycle
- Sibling switches still trigger clean remounts with stable key

* perf: stabilize root MultiMessage key across new conversation lifecycle

When a user sends their first message in a new conversation,
conversationId transitions from null/'new' to the server-assigned
UUID. MessagesView used key={conversationId} on the root MultiMessage,
so this transition destroyed the entire message tree and rebuilt it
from scratch — causing all MessageIcons to unmount/remount (visible
as image flickering).

Use a ref-based stable key that captures the first real conversationId
and only changes on genuine conversation switches (navigating to a
different conversation), not on the null→UUID transition within the
same conversation.

* debug: add mount/unmount lifecycle tracking to MessageIcon

Adds icon_lifecycle logs (MOUNT/UNMOUNT) and render count to
distinguish between fresh mounts (memo comparator not called)
and internal re-renders (hook bypassing memo).

Enable: localStorage.setItem('DEBUG_LOGGING', 'icon_lifecycle,icon_data,icon_memo_diff')

* debug: add key and root tracking to MultiMessage and MessagesView

Logs multi_message_key (stableKey, messageId, parentMessageId, route)
and messages_view_key (rootKey, conversationId) to trace which key
changes trigger unmount/remount cycles.

Enable: localStorage.setItem('DEBUG_LOGGING', 'icon_lifecycle,icon_data,icon_memo_diff,multi_message_key,messages_view_key')

* perf: remove key from root MultiMessage to prevent tree destruction

The ref-based stable key still changed during 'new' → real UUID
transition, destroying the entire tree. The root MultiMessage is the
sole child at its position, so React reuses the instance via
positional reconciliation without any key. The messageId prop
(conversationId) naturally resets Recoil siblingIdxFamily state on
conversation switches.

* perf: remove unstable keys from MultiMessage to prevent SSE lifecycle remounts

Both messageId and parentMessageId change during the SSE lifecycle
(client UUID → CREATED server ID → FINAL server ID), making neither
viable as a stable React key. Each key change caused React to destroy
and recreate the entire message component subtree, including all
memoized children — visible as icon/image flickering.

Remove explicit keys entirely and rely on React's positional
reconciliation. MultiMessage always renders exactly one child at
the same position, so React reuses the component instance and
updates props in place. The existing memo comparators on
ContentRender/MessageRender handle field-level diffing correctly.

Update tests to verify: key={messageId} causes 3 mounts/2 unmounts
per lifecycle, while no key causes 1 mount/0 unmounts.

* perf: remove unstable keys from child MultiMessage in message wrappers

Message.tsx, MessageContent.tsx, and MessageParts.tsx each render a
child MultiMessage with key={messageId} for the current message's
children. Since messageId changes during the SSE lifecycle (CREATED
event replaces the user message ID), the child MultiMessage gets
destroyed and recreated, unmounting the entire agent response subtree
including its MessageIcon.

Remove these keys for the same reason as the parent MultiMessage:
each child MultiMessage renders exactly one child at a fixed position,
so positional reconciliation correctly reuses the instance.

* chore: remove MultiMessage key tests — they test React behavior, not our code

The tests verified that key={messageId} causes remounts while no key
doesn't, but this is React's own reconciliation behavior. No unit test
can prevent someone from re-adding a key prop to JSX. The JSDoc comments
on MultiMessage document the decision and rationale.
2026-04-02 22:29:54 -04:00
Danny Avila
7e2b51697e
🪢 refactor: Eliminate Unnecessary Re-renders During Message Streaming (#12454)
Some checks failed
Publish `librechat-data-provider` to NPM / build (push) Has been cancelled
Publish `@librechat/data-schemas` to NPM / build-and-publish (push) Has been cancelled
Docker Dev Images Build / build (Dockerfile, librechat-dev, node) (push) Has been cancelled
Docker Dev Images Build / build (Dockerfile.multi, librechat-dev-api, api-build) (push) Has been cancelled
Sync Locize Translations & Create Translation PR / Sync Translation Keys with Locize (push) Has been cancelled
Publish `librechat-data-provider` to NPM / publish-npm (push) Has been cancelled
Sync Locize Translations & Create Translation PR / Create Translation PR on Version Published (push) Has been cancelled
* refactor: add TMessageChatContext type for stable context passing

Defines a type for a stable context object that wrapper components
pass to memo'd message components, avoiding direct ChatContext
subscriptions that bypass React.memo during streaming.

* perf: remove ChatContext subscription from useMessageActions

useMessageActions previously called useChatContext() inside memo'd
components (MessageRender, ContentRender), bypassing React.memo
when isSubmitting changed during streaming. Now accepts a stable
chatContext param instead, using a ref for the isSubmitting guard
in regenerateMessage.

Also stabilizes handleScroll in useMessageProcess by using a ref
for isSubmitting instead of including it in useCallback deps.

* perf: pass stable chatContext to memo'd message components

Wrapper components (Message, MessageContent) now create a stable
chatContext object via useMemo with a getter-backed isSubmitting,
and compute effectiveIsSubmitting (false for non-latest messages).

This ensures MessageRender and ContentRender (both React.memo'd)
only re-render for the latest message during streaming, preventing
unnecessary re-renders of all prior messages and their SubRow,
HoverButtons, and SiblingSwitch children.

* perf: add custom memo comparators to prevent message reference re-renders

buildTree creates new message objects on every streaming update for
ALL messages, not just the changed one. This defeats React.memo's
default shallow comparison since the message prop has a new reference
even when the content hasn't changed.

Custom areEqual comparators now compare message by key fields
(messageId, text, error, depth, children length, etc.) instead of
reference equality, preventing unnecessary re-renders of SubRow,
Files, HoverButtons and other children for non-latest messages.

* perf: memoize ChatForm children to prevent streaming re-renders

- Wrap StopButton in React.memo
- Wrap AudioRecorder in React.memo, use ref for isSubmitting in
  onTranscriptionComplete callback to stabilize it
- Remove useChatContext() from FileFormChat (bypassed its memo
  during streaming), accept files/setFiles/setFilesLoading as
  props from ChatForm instead

* perf: stabilize ChatForm child props to prevent cascading re-renders

ChatForm re-renders frequently during streaming (ChatContext changes).
This caused StopButton and AttachFileChat/AttachFileMenu to re-render
despite being memo'd, because their props were new references each time.

- Wrap handleStopGenerating in a ref-based stable callback so StopButton
  always receives the same function reference
- Create stableConversation via useMemo keyed on rendering-relevant
  fields only (conversationId, endpoint, agent_id, etc.), so
  AttachFileChat and FileFormChat don't re-render from unrelated
  conversation metadata updates (e.g., title generation)

* perf: remove ChatContext subscription from AttachFileMenu and FileFormChat

Both components used useFileHandling() which internally calls
useChatContext(), bypassing their React.memo wrappers and causing
re-renders on every streaming chunk.

Switch to useFileHandlingNoChatContext() which accepts file state
as parameters. The state (files, setFiles, setFilesLoading,
conversation) is passed down from ChatForm → AttachFileChat →
AttachFileMenu as props, keeping the memo chain intact.

* fix: update imports and test mocks for useFileHandlingNoChatContext

- Re-export useFileHandlingNoChatContext from hooks barrel
- Import from ~/hooks instead of direct path for test compatibility
- Add useToastContext mock to @librechat/client in AttachFileMenu tests
  since useFileHandlingNoChatContext runs the core hook which needs it
- Add useFileHandlingNoChatContext to ~/hooks test mock

* perf: fix remaining ChatForm streaming re-renders

- Switch AttachFileMenu from useSharePointFileHandling (subscribes to
  ChatContext) to useSharePointFileHandlingNoChatContext with explicit
  file state props
- Memoize ChatForm textarea onFocus/onBlur handlers with useCallback
  to prevent TextareaAutosize re-renders (inline arrow functions and
  .bind() created new references on every ChatForm render)
- Update AttachFileMenu test mocks for new hook variants

* refactor: add displayName to ChatForm for React DevTools

* perf: prevent ChatForm re-renders during streaming via wrapper pattern

ChatForm was re-rendering on every streaming chunk because it subscribed
to useChatContext() internally, and the ChatContext value changed
frequently during streaming.

Extract context subscription into a ChatFormWrapper that:
- Subscribes to useChatContext() (re-renders on every chunk, cheap)
- Stabilizes conversation via selective useMemo
- Stabilizes handleStopGenerating via ref-based callback
- Passes individual stable values as props to ChatForm

ChatForm (memo'd) now receives context values as props instead of
subscribing directly. Since individual values (files, setFiles,
isSubmitting, etc.) are stable references during streaming, ChatForm's
memo prevents re-renders entirely — it only re-renders when isSubmitting
actually toggles (2x per stream: start/end).

* perf: stabilize newConversation prop and memoize CollapseChat

- Wrap newConversation in ref-based stable callback in ChatFormWrapper
  (was the remaining unstable prop causing ChatForm to re-render)
- Wrap CollapseChat in React.memo to prevent re-renders from parent

* perf: memoize useAddedResponse return value

useAddedResponse returned a new object literal on every render,
causing AddedChatContext.Provider to trigger re-renders of all
consumers (including ChatForm) on every streaming chunk. Wrap in
useMemo so the context value stays referentially stable.

* perf: memoize TextareaHeader to prevent re-renders from ChatForm

* perf: address review findings for streaming render optimization

Finding 1: Switch AttachFile.tsx from useFileHandling to
useFileHandlingNoChatContext, closing the optimization hole for
standard (non-agent) chat endpoints.

Finding 2: Replace content reference equality with length comparison
in both memo comparators — safer against buildTree array reconstruction.

Finding 3: Add conversation?.model to stableConversation deps in
ChatFormWrapper so file uploads use the correct model after switches.

Finding 4/14: Fix stableNewConversation to explicitly return the
underlying call's result instead of discarding it via `as` cast.

Finding 5/6: Extract useMemoizedChatContext hook shared by Message.tsx
and MessageContent.tsx — eliminates ~70 lines of duplication and
stabilizes chatContext.conversation via selective useMemo to prevent
post-stream metadata updates from re-rendering all messages.

Finding 8: Use TMessage type for regenerate param instead of
Record<string, unknown>.

Finding 9: Use FileSetter alias in FileFormChat instead of inline type.

Finding 11: Fix pre-existing broken throttle in useMessageProcess —
was creating a new throttle instance per call, providing zero
deduplication. Now retains the instance via useMemo.

Finding 12: Initialize isSubmittingRef with chatContext.isSubmitting
instead of false for consistency.

Finding 13: Add ChatFormWrapper displayName.

* fix: revert content comparison to reference equality in memo comparators

The length-based comparison (content?.length) missed updates within
existing content parts during streaming — text chunks update a part's
content without changing the array length, so the comparator returned
true and skipped re-renders for the latest message.

Reference equality (===) is correct here: buildTree preserves content
array references for unchanged messages via shallow spread, while
React Query gives the latest message a new reference when its content
updates during streaming.

* fix: cancel throttled handleScroll on unmount and remove unused import

* fix: use chatContext getter directly in regenerateMessage callback

The local isSubmittingRef was stale for non-latest messages (which
don't re-render during streaming by design). chatContext.isSubmitting
is a getter backed by the wrapper's ref, so reading it at call-time
always returns the current value regardless of whether the component
has re-rendered.

* fix: remove unused useCallback import from useMemoizedChatContext

* fix: pass global isSubmitting to HoverButtons for action gating

HoverButtons uses isSubmitting via useGenerationsByLatest to disable
regenerate and hide edit buttons during streaming. Passing the
effective value (false for non-latest messages) re-enabled those
actions mid-stream, risking overlapping edits/regenerations.

Use chatContext.isSubmitting (getter, always returns current value)
for HoverButtons while keeping the effective value for rendering-only
UI (cursor, placeholder, streaming indicator).

* fix: address second review — stale HoverButtons, messages dep, cleanup

- Add isSubmitting to chatContext useMemo deps in useMemoizedChatContext
  so HoverButtons correctly updates when streaming starts/ends (2 extra
  re-renders per session, belt-and-suspenders for post-stream state)
- Change conversation?.messages?.length dep to boolean in ChatFormWrapper
  stableConversation — only need 0↔1+ transition for landing page check,
  not exact count on every message addition
- Add defensive comment at chatContext destructuring point in
  useMessageActions explaining why isSubmitting must not be destructured
- Remove dead mockUseFileHandling.mockReturnValue from AttachFileMenu tests

* chore: remove dead useFileHandling mock artifacts from AttachFileMenu tests

* fix: resolve eslint warnings for useMemo dependencies

- Extract complex expression (conversation?.messages?.length ?? 0) > 0
  to hasMessages variable for static analysis in ChatFormWrapper
- Add eslint-disable for intentional isSubmitting dep in
  useMemoizedChatContext (forces new chatContext reference on streaming
  start/end so HoverButtons re-renders)
2026-03-29 17:05:12 -04:00
Danny Avila
5209f1dc9e
refactor: Optimize Message Re-renders (#12097)
* 🔄 refactor: Update Artifacts and Messages Contexts to Use Latest Message ID and Depth

- Modified ArtifactsContext to retrieve latestMessage using Recoil state management.
- Updated MessagesViewContext to replace latestMessage with latestMessageId and latestMessageDepth for improved clarity and consistency.
- Adjusted various components (HoverButtons, MessageParts, MessageRender, ContentRender) to utilize latestMessageId instead of the entire message object, enhancing performance and reducing unnecessary re-renders.
- Refactored useChatHelpers to extract latestMessageId and latestMessageDepth, streamlining message handling across the application.

* refactor: Introduce PartWithContext Component for Optimized Message Rendering

- Added a new PartWithContext component to encapsulate message part rendering logic, improving context management and reducing redundancy in the ContentParts component.
- Updated MessageRender to utilize the new PartWithContext, streamlining the context provider setup and enhancing code clarity.
- Refactored related logic to ensure proper context values are passed, improving maintainability and performance in message rendering.

* refactor: Update Components to Use Function Declarations and Improve Readability

- Refactored several components (MessageContainer, Markdown, MarkdownCode, MarkdownCodeNoExecution, MarkdownAnchor, MarkdownParagraph, MarkdownImage, TextPart, PlaceholderRow) to use function declarations instead of arrow functions, enhancing readability and consistency across the codebase.
- Added display names to memoized components for better debugging and profiling in React DevTools.
- Improved overall code clarity and maintainability by standardizing component definitions.

* refactor: Standardize MessageRender and ContentRender Components for Improved Clarity

- Refactored MessageRender and ContentRender components to use function declarations, enhancing readability and consistency.
- Streamlined props handling by removing unnecessary parameters and improving the use of hooks for state management.
- Updated memoization and rendering logic to optimize performance and reduce unnecessary re-renders.
- Enhanced overall code clarity and maintainability by standardizing component definitions and structure.

* refactor: Enhance Header Component with Memoization for Performance

- Refactored the Header component to utilize React's memoization by wrapping it with the memo function, improving rendering performance by preventing unnecessary re-renders.
- Changed the export to a memoized version of the Header component, ensuring better debugging with a display name.
- Maintained overall code clarity and consistency in component structure.

* refactor: Transition Components to Use Recoil for State Management

- Updated multiple components (AddMultiConvo, TemporaryChat, HeaderNewChat, PresetsMenu, ModelSelectorChatContext) to utilize Recoil for state management, enhancing consistency and performance.
- Replaced useChatContext with Recoil selectors and atoms, improving data flow and reducing unnecessary re-renders.
- Introduced new selectors for conversation ID and endpoint retrieval, streamlining component logic and enhancing maintainability.
- Improved overall code clarity by standardizing state management practices across components.

* refactor: Integrate getConversation Callback for Enhanced State Management

- Updated multiple components (Mention, ModelSelectorChatContext, ModelSelectorContext, FavoritesList) to utilize a getConversation callback instead of directly accessing conversation state, improving encapsulation and maintainability.
- Refactored useSelectMention hook to accept getConversation, streamlining conversation retrieval and enhancing code clarity.
- Introduced new Recoil selectors for conversation properties, ensuring consistent state management across components.
- Enhanced overall code structure by standardizing the approach to conversation handling, reducing redundancy and improving performance.

* refactor: Optimize LiveAnnouncer Context Value with useMemo

- Updated the LiveAnnouncer component to utilize useMemo for context value creation, enhancing performance by preventing unnecessary recalculations of the context object.
- Improved overall code clarity and maintainability by ensuring that context values are only recomputed when their dependencies change.

* refactor: Update AgentPanelSwitch to Use Recoil for Agent ID Management

- Refactored AgentPanelSwitch component to utilize Recoil for retrieving the current agent ID, replacing the previous use of chat context.
- Improved state management by ensuring the agent ID is derived from Recoil, enhancing code clarity and maintainability.
- Adjusted useEffect dependencies to reflect the new state management approach, streamlining the component's logic.

* refactor: Enhance useLocalize Hook with useCallback for Improved Performance

- Updated the useLocalize hook to utilize useCallback for the translation function, optimizing performance by preventing unnecessary re-creations of the function on each render.
- Improved code clarity by ensuring that the translation function is memoized, enhancing maintainability and efficiency in localization handling.

* refactor: Rename useCreateConversationAtom to useSetConversationAtom for Clarity

- Updated the hook name from useCreateConversationAtom to useSetConversationAtom to better reflect its functionality in managing conversation state.
- Introduced a new implementation for setting conversation state, enhancing clarity and maintainability in the codebase.
- Adjusted related references in the useNewConvo hook to align with the new naming convention.

* refactor: Enhance useKeyDialog Hook with useMemo and useCallback for Improved Performance

- Updated the useKeyDialog hook to utilize useMemo for returning the dialog state and handlers, optimizing performance by preventing unnecessary recalculations.
- Refactored the onOpenChange function to use useCallback, ensuring it only changes when its dependencies do, enhancing maintainability and clarity in the code.
- Improved overall code structure and readability by streamlining the hook's logic and dependencies.

* feat: Add useRenderChangeLog Hook for Debugging Render Changes

- Introduced a new hook, useRenderChangeLog, that logs changes in tracked values between renders when a debug flag is enabled.
- Utilizes useEffect and useRef to track previous values and identify changes, enhancing debugging capabilities for component renders.
- Provides detailed console output for initial renders and value changes, improving developer insights during the rendering process.

* refactor: Update useSelectAgent Hook for Improved State Management and Performance

- Refactored the useSelectAgent hook to utilize useRecoilCallback for fetching conversation data, enhancing state management and performance.
- Replaced the use of useChatContext with a more efficient approach, streamlining the logic for selecting agents and updating conversations.
- Improved error handling and ensured asynchronous operations are properly awaited, enhancing reliability in agent selection and data fetching processes.

* refactor: Optimize useDefaultConvo Hook with useCallback for Improved Performance

- Refactored the getDefaultConversation function within the useDefaultConvo hook to utilize useCallback, enhancing performance by memoizing the function and preventing unnecessary re-creations on re-renders.
- Streamlined the logic for cleaning input and output in the conversation object, improving code clarity and maintainability.
- Ensured that dependencies for useCallback are correctly set, enhancing the reliability of the hook's behavior.

* refactor: Optimize Agent Components with Memoization for Improved Performance

- Refactored multiple agent-related components (AgentAvatar, AgentCategorySelector, AgentSelect, DeleteButton, FileContext, FileSearch, Files) to utilize React.memo for memoization, enhancing rendering performance by preventing unnecessary re-renders.
- Updated the FileRow component to make setFilesLoading optional, improving flexibility in file handling.
- Streamlined component logic and improved maintainability by ensuring that props are compared efficiently in memoized components.

* refactor: Enhance File Handling and Agent Components for Improved Performance

- Refactored multiple components (DeleteButton, FileContext, FileSearch, Files) to utilize new file handling hooks that separate chat context from file operations, improving performance and maintainability.
- Introduced useFileHandlingNoChatContext and useSharePointFileHandlingNoChatContext hooks to streamline file handling logic, enhancing flexibility in managing file states.
- Updated DeleteButton to improve conversation state management and ensure proper handling of agent deletions, enhancing user experience.
- Optimized imports and component structure for better clarity and organization across the affected files.

* refactor: Enhance useRenderChangeLog Hook with Improved Type Safety and Documentation

- Updated the useRenderChangeLog hook to improve type safety by specifying the value types as string, number, boolean, null, or undefined.
- Enhanced documentation to clarify usage and enablement of the debug feature, ensuring better developer insights during rendering.
- Added a production check to prevent logging in production builds, optimizing performance and maintaining clean console output.

* chore: imports

* refactor: Replace useRecoilCallback with useGetConversation Hook for Improved Clarity and Performance

- Refactored multiple components (AddMultiConvo, ModelSelectorChatContext, FavoritesList, useSelectAgent, usePresets) to utilize the new useGetConversation hook, enhancing clarity and reducing complexity by eliminating the use of useRecoilCallback.
- Streamlined conversation retrieval logic across components, improving maintainability and performance.
- Updated imports and component structure for better organization and readability.

* refactor: Enhance Memoization in DeleteButton Component for Improved Performance

- Updated the memoization logic in the DeleteButton component to include a comparison for the setCurrentAgentId prop, ensuring more efficient re-renders.
- This change improves performance by preventing unnecessary updates when the agent ID and current agent ID remain unchanged.

* chore: fix test

* refactor: Improve Memoization Logic in AgentSelect Component

- Updated the memoization comparison in the AgentSelect component to directly compare agentQuery.data objects, enhancing performance by ensuring accurate re-renders.
- Refactored the useCreateConversationAtom function to streamline the logic for updating conversation keys, improving clarity and maintainability.

* refactor: Simplify State Management in DeleteButton Component

- Removed unnecessary setConversationOption function, streamlining the logic for updating conversation state after agent deletion.
- Updated the conversation state directly within the deleteAgent mutation, improving clarity and maintainability of the component.
- Refactored conversationByKeySelector to directly reference conversationByIndex, enhancing performance and reducing complexity in state retrieval.

* refactor: Remove Unused Conversation Prop from Mention Component

- Eliminated the conversation prop from the Mention component, simplifying its interface and reducing unnecessary dependencies.
- Updated the ChatForm component to reflect this change, enhancing clarity and maintainability of the codebase.
- Introduced useGetConversation hook for improved conversation retrieval logic, streamlining the component's functionality.

* refactor: Simplify File Handling State Management Across Components

- Removed the unused setFilesLoading function from FileContext, FileSearch, and Files components, streamlining the file handling state management.
- Updated the FileHandlingState type to make setFilesLoading optional, enhancing flexibility in file operations.
- Improved memoization logic by directly referencing necessary state properties, ensuring better performance and maintainability.

* refactor: Update ArtifactsContext for Improved State Management

- Replaced the useChatContext hook with direct Recoil state retrieval for isSubmitting, latestMessage, and conversationId, simplifying the context provider's logic.
- Enhanced memoization by ensuring relevant state properties are directly referenced, improving performance and maintainability.
- Streamlined the context value creation to reflect the updated state management approach.

* refactor: Adjust Memoization Logic in ArtifactsContext for Consistency

- Updated the memoization logic in the ArtifactsProvider to ensure the messageId is consistently referenced, improving clarity and maintainability.
- This change enhances the performance of the context provider by ensuring all relevant properties are included in the memoization dependencies.
2026-03-06 00:03:32 -05:00
Danny Avila
439bc98682
⏸ refactor: Improve UX for Parallel Streams (Multi-Convo) (#11096)
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
* 🌊 feat: Implement multi-conversation feature with added conversation context and payload adjustments

* refactor: Replace isSubmittingFamily with isSubmitting across message components for consistency

* feat: Add loadAddedAgent and processAddedConvo for multi-conversation agent execution

* refactor: Update ContentRender usage to conditionally render PlaceholderRow based on isLast and isSubmitting

* WIP: first pass, sibling index

* feat: Enhance multi-conversation support with agent tracking and display improvements

* refactor: Introduce isEphemeralAgentId utility and update related logic for agent handling

* refactor: Implement createDualMessageContent utility for sibling message display and enhance useStepHandler for added conversations

* refactor: duplicate tools for added agent if ephemeral and primary agent is also ephemeral

* chore: remove deprecated multimessage rendering

* refactor: enhance dual message content creation and agent handling for parallel rendering

* refactor: streamline message rendering and submission handling by removing unused state and optimizing conditional logic

* refactor: adjust content handling in parallel mode to utilize existing content for improved agent display

* refactor: update @librechat/agents dependency to version 3.0.53

* refactor: update @langchain/core and @librechat/agents dependencies to latest versions

* refactor: remove deprecated @langchain/core dependency from package.json

* chore: remove unused SearchToolConfig and GetSourcesParams types from web.ts

* refactor: remove unused message properties from Message component

* refactor: enhance parallel content handling with groupId support in ContentParts and useStepHandler

* refactor: implement parallel content styling in Message, MessageRender, and ContentRender components. use explicit model name

* refactor: improve agent ID handling in createDualMessageContent for dual message display

* refactor: simplify title generation in AddedConvo by removing unused sender and preset logic

* refactor: replace string interpolation with cn utility for className in HoverButtons component

* refactor: enhance agent ID handling by adding suffix management for parallel agents and updating related components

* refactor: enhance column ordering in ContentParts by sorting agents with suffix management

* refactor: update @librechat/agents dependency to version 3.0.55

* feat: implement parallel content rendering with metadata support

- Added `ParallelContentRenderer` and `ParallelColumns` components for rendering messages in parallel based on groupId and agentId.
- Introduced `contentMetadataMap` to store metadata for each content part, allowing efficient parallel content detection.
- Updated `Message` and `ContentRender` components to utilize the new metadata structure for rendering.
- Modified `useStepHandler` to manage content indices and metadata during message processing.
- Enhanced `IJobStore` interface and its implementations to support storing and retrieving content metadata.
- Updated data schemas to include `contentMetadataMap` for messages, enabling multi-agent and parallel execution scenarios.

* refactor: update @librechat/agents dependency to version 3.0.56

* refactor: remove unused EPHEMERAL_AGENT_ID constant and simplify agent ID check

* refactor: enhance multi-agent message processing and primary agent determination

* refactor: implement branch message functionality for parallel responses

* refactor: integrate added conversation retrieval into message editing and regeneration processes

* refactor: remove unused isCard and isMultiMessage props from MessageRender and ContentRender components

* refactor: update @librechat/agents dependency to version 3.0.60

* refactor: replace usage of EPHEMERAL_AGENT_ID constant with isEphemeralAgentId function for improved clarity and consistency

* refactor: standardize agent ID format in tests for consistency

* chore: move addedConvo property to the correct position in payload construction

* refactor: rename agent_id values in loadAgent tests for clarity

* chore: reorder props in ContentParts component for improved readability

* refactor: rename variable 'content' to 'result' for clarity in RedisJobStore tests

* refactor: streamline useMessageActions by removing duplicate handleFeedback assignment

* chore: revert placeholder rendering logic MessageRender and ContentRender components to original

* refactor: implement useContentMetadata hook for optimized content metadata handling

* refactor: remove contentMetadataMap and related logic from the codebase and revert back to agentId/groupId in content parts

- Eliminated contentMetadataMap from various components and services, simplifying the handling of message content.
- Updated functions to directly access agentId and groupId from content parts instead of relying on a separate metadata map.
- Adjusted related hooks and components to reflect the removal of contentMetadataMap, ensuring consistent handling of message content.
- Updated tests and documentation to align with the new structure of message content handling.

* refactor: remove logging from groupParallelContent function to clean up output

* refactor: remove model parameter from TBranchMessageRequest type for simplification

* refactor: enhance branch message creation by stripping metadata for standalone content

* chore: streamline branch message creation by simplifying content filtering and removing unnecessary metadata checks

* refactor: include attachments in branch message creation for improved content handling

* refactor: streamline agent content processing by consolidating primary agent identification and filtering logic

* refactor: simplify multi-agent message processing by creating a dedicated mapping method and enhancing content filtering

* refactor: remove unused parameter from loadEphemeralAgent function for cleaner code

* refactor: update groupId handling in metadata to only set when provided by the server
2025-12-25 01:43:54 -05:00
Danny Avila
f9060fa25f
🔧 chore: Update ESLint Config & Run Linter (#10986)
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
2025-12-15 17:55:25 -05:00
Danny Avila
d59b62174f
🪨 feat: AWS Bedrock support (#3935)
* feat: Add BedrockIcon component to SVG library

* feat: EModelEndpoint.bedrock

* feat: first pass, bedrock chat. note: AgentClient is returning `agents` as conversation.endpoint

* fix: declare endpoint in initialization step

* chore: Update @librechat/agents dependency to version 1.4.5

* feat: backend content aggregation for agents/bedrock

* feat: abort agent requests

* feat: AWS Bedrock icons

* WIP: agent provider schema parsing

* chore: Update EditIcon props type

* refactor(useGenerationsByLatest): make agents and bedrock editable

* refactor: non-assistant message content, parts

* fix: Bedrock response `sender`

* fix: use endpointOption.model_parameters not endpointOption.modelOptions

* fix: types for step handler

* refactor: Update Agents.ToolCallDelta type

* refactor: Remove unnecessary assignment of parentMessageId in AskController

* refactor: remove unnecessary assignment of parentMessageId (agent request handler)

* fix(bedrock/agents): message regeneration

* refactor: dynamic form elements using react-hook-form Controllers

* fix: agent icons/labels for messages

* fix: agent actions

* fix: use of new dynamic tags causing application crash

* refactor: dynamic settings touch-ups

* refactor: update Slider component to allow custom track class name

* refactor: update DynamicSlider component styles

* refactor: use Constants value for GLOBAL_PROJECT_NAME (enum)

* feat: agent share global methods/controllers

* fix: agents query

* fix: `getResponseModel`

* fix: share prompt a11y issue

* refactor: update SharePrompt dialog theme styles

* refactor: explicit typing for SharePrompt

* feat: add agent roles/permissions

* chore: update @librechat/agents dependency to version 1.4.7 for tool_call_ids edge case

* fix(Anthropic): messages.X.content.Y.tool_use.input: Input should be a valid dictionary

* fix: handle text parts with tool_call_ids and empty text

* fix: role initialization

* refactor: don't make instructions required

* refactor: improve typing of Text part

* fix: setShowStopButton for agents route

* chore: remove params for now

* fix: add streamBuffer and streamRate to help prevent 'Overloaded' errors from Anthropic API

* refactor: remove console.log statement in ContentRender component

* chore: typing, rename Context to Delete Button

* chore(DeleteButton): logging

* refactor(Action): make accessible

* style(Action): improve a11y again

* refactor: remove use/mention of mongoose sessions

* feat: first pass, sharing agents

* feat: visual indicator for global agent, remove author when serving to non-author

* wip: params

* chore: fix typing issues

* fix(schemas): typing

* refactor: improve accessibility of ListCard component and fix console React warning

* wip: reset templates for non-legacy new convos

* Revert "wip: params"

This reverts commit f8067e91d4.

* Revert "refactor: dynamic form elements using react-hook-form Controllers"

This reverts commit 2150c4815d.

* fix(Parameters): types and parameter effect update to only update local state to parameters

* refactor: optimize useDebouncedInput hook for better performance

* feat: first pass, anthropic bedrock params

* chore: paramEndpoints check for endpointType too

* fix: maxTokens to use coerceNumber.optional(),

* feat: extra chat model params

* chore: reduce code repetition

* refactor: improve preset title handling in SaveAsPresetDialog component

* refactor: improve preset handling in HeaderOptions component

* chore: improve typing, replace legacy dialog for SaveAsPresetDialog

* feat: save as preset from parameters panel

* fix: multi-search in select dropdown when using Option type

* refactor: update default showDefault value to false in Dynamic components

* feat: Bedrock presets settings

* chore: config, fix agents schema, update config version

* refactor: update AWS region variable name in bedrock options endpoint to BEDROCK_AWS_DEFAULT_REGION

* refactor: update baseEndpointSchema in config.ts to include baseURL property

* refactor: update createRun function to include req parameter and set streamRate based on provider

* feat: availableRegions via config

* refactor: remove unused demo agent controller file

* WIP: title

* Update @librechat/agents to version 1.5.0

* chore: addTitle.js to handle empty responseText

* feat: support images and titles

* feat: context token updates

* Refactor BaseClient test to use expect.objectContaining

* refactor: add model select, remove header options params, move side panel params below prompts

* chore: update models list, catch title error

* feat: model service for bedrock models (env)

* chore: Remove verbose debug log in AgentClient class following stream

* feat(bedrock): track token spend; fix: token rates, value key mapping for AWS models

* refactor: handle streamRate in `handleLLMNewToken` callback

* chore: AWS Bedrock example config in `.env.example`

* refactor: Rename bedrockMeta to bedrockGeneral in settings.ts and use for AI21 and Amazon Bedrock providers

* refactor: Update `.env.example` with AWS Bedrock model IDs URL and additional notes

* feat: titleModel support for bedrock

* refactor: Update `.env.example` with additional notes for AWS Bedrock model IDs
2024-09-09 12:06:59 -04:00