[pull] main from danny-avila:main#118
Merged
pull[bot] merged 12 commits intoinnFactory:mainfrom May 7, 2026
Merged
Conversation
* fix: honor Anthropic Vertex config * chore: format Anthropic Vertex config fix
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix: add gpt-5.5 token definitions * fix: align gpt-5.5 context limit
* fix: Preserve unicode filenames * fix: Cap unicode filenames by bytes * fix: Preserve clean artifact directories * fix: Disambiguate normalized artifact names
) * feat(ui): add message navigation strip and redesign scroll-to-bottom button Add a floating vertical navigation strip on the right edge of the chat area that lets users jump between messages quickly. Each message gets an indicator line (wider for assistant, narrower for user) with HoverCard previews showing truncated message text. IntersectionObserver tracks which messages are currently visible and highlights their indicators. Redesign the scroll-to-bottom button: solid backgrounds instead of semi-transparent, clean enter/exit animations without twist/rotate, no hover float animation, positioned at the right edge of the chat form instead of center. * fix(ui): prevent message nav layout shift on scroll Use a fixed-height container for each indicator so the nav strip maintains consistent dimensions when indicators transition between active and inactive states. * fix(ui): debounce message nav refresh and persist visibility state Debounce entry refresh (200ms) to avoid thrashing from rapid DOM mutations during code block rendering. Persist the visible message set across IntersectionObserver reconnections to prevent momentary empty state that disabled navigation buttons. * fix(ui): prevent nav buttons from disabling during fast scroll - Fall back to last known active index when IntersectionObserver reports no visible messages during rapid scrolling - Lower intersection threshold from 10% to 1% for long messages - Fix preview text to skip the message header (Prompt N: username) * fix(ui): scroll to message start when using nav arrow buttons Arrow buttons now use block: 'start' to always scroll to the top of the target message. Indicator dots keep block: 'nearest' for minimal repositioning on direct clicks. * fix(ui): account for header offset when scrolling to messages Use manual scrollTo with a 56px offset to prevent the fixed header from covering the top of the target message when using arrow buttons. * fix(ui): improve message nav scrolling and visual subtlety - Up button scrolls to current message top first before jumping to previous, preventing skipped messages on long content - Down button consistently scrolls to the start of the next message - Nav strip is faded (opacity 30%) by default, fully visible on hover - Background, buttons, and indicators all appear on hover of the nav area using group hover coordination * fix(ui): use native scroll-margin-top for reliable message navigation Replace manual scrollTo calculations with scrollIntoView + CSS scroll-margin-top on .message-render elements. The browser handles scroll offset natively, eliminating positioning errors during smooth scroll animations. * fix(ui): use firstActiveIndex for both nav directions Use firstActiveIndex (topmost visible message) for both up and down navigation. Down now advances one message at a time from what the user is currently reading instead of jumping past all visible messages. Remove unused lastActiveIndex. * fix(ui): address PR review feedback - Scope getMessageEntries query to scroll container instead of document - Include preview text in entries equality check to catch content updates during streaming/edits - Move scroll button transition to base state so release animates smoothly instead of snapping back * fix(ui): make message nav scroll precise and chevrons reliable - Bump .message-render scroll-margin-top from 1rem to 4rem so messages land below the 52px absolute gradient header instead of behind it. - Drive chevron jumps from live scrollTop + offsetTop comparison rather than the IntersectionObserver-derived firstActiveIndex, which lagged behind rapid clicks and treated any 1px-visible message as "current". - Track canGoUp / canGoDown from the same scroll-position comparison so the disabled state matches what the buttons will actually do. - Auto-center the indicator column on the visible message range and smooth-scroll it via rAF so 500+ indicators stay at 60fps. - Pull entry data from useGetMessagesByConvoId (with a DOM fallback) so previews are state-backed instead of scraped from rendered markup. - Memoize MessageIndicator and filter MutationObserver to .message-render add/remove only. - Add 5 i18n keys (com_ui_message_nav*) for nav and indicator labels. * perf(ui): skip off-screen message layout and fix resulting scroll drift Large conversations used to freeze the main thread during sidebar toggles because every animated frame had to relayout every message. With ~3000 message elements on this branch: avg frame 650ms, max 1701ms (~1.5fps) during the 300ms transition. Adding `content-visibility: auto` with `contain-intrinsic-size: auto 200px` on .message-render lets the browser skip layout/paint for messages outside the viewport, dropping avg frame to 33ms and max to 74ms (~30fps, feels responsive). content-visibility comes with a trade-off though: off-screen messages use the 200px intrinsic-size estimate until they're measured. That broke indicator-click scrolling on long conversations, landing 1-2 messages off the target because scrollIntoView computed its target scrollTop once with stale estimates, and intermediate messages shrunk/grew as they rendered during the smooth scroll. Replaced scrollIntoView with a manual rAF scroll that re-reads the target's getBoundingClientRect every frame and eases toward the *current* target. Verified drift=0 across fake-0, fake-50, fake-250, fake-450 (messages near the bottom naturally land higher than scroll-margin when the container is already at max scroll — expected). Also two small MessageNav.tsx hot-path cleanups: - Use col.children[i] instead of col.querySelector by data-msg-id for the indicator-column centering lookup (entries map 1:1 to column children since HoverCardTrigger asChild forwards to the button). - Compare visibility set contents before setActiveIds, so an IntersectionObserver flush with unchanged membership doesn't force a re-render and 500x memo comparisons. * revert(ui): drop content-visibility on .message-render Didn't deliver the expected sidebar-toggle perf win in real-world usage, and its intrinsic-size estimation introduced the exact kind of scroll drift we then had to work around. The rAF scroll in MessageNav is orthogonal to this and stays — it works fine with or without content-visibility. * fix(ui): address PR review — a11y, tests, and MessageNav correctness - ScrollToBottom aria-label now runs through useLocalize instead of being hardcoded English. Added com_ui_scroll_to_bottom translation key. - MessageNav nav expands on keyboard focus-within, not just pointer hover. - Indicator buttons expose aria-current="true" for the active message and get a visible focus-visible ring. Chevron buttons get the same ring so keyboard users can see focus. - Cancel in-flight rAF scrolls when a new navigation starts, so clicking a second indicator mid-animation doesn't race the first loop on container.scrollTop. - Invalidate the cached offsetsTop/offsetsBottom arrays via a ResizeObserver on the scroll content. Previously heights that changed after mount (code blocks rendering, images loading) left canGoUp / canGoDown and the indicator-column centering reading stale positions. - Observe IntersectionObserver entries incrementally. The observer is now created once per scroll container and entries add/remove on change instead of the whole observer being torn down and rebuilt for every new message. - memo() the default export so parent re-renders don't cascade through MessageNav when entries/activeIds haven't changed. - Add 18-test suite covering rendering threshold, user/assistant indicator styling, preview sourcing (React Query vs DOM fallback vs truncation), accessibility (aria-label, aria-current, chevron disabled state), click-driven rAF scroll + cancellation, and observer lifecycle (observe on mount, incremental sync, unobserve on removal, disconnect on unmount). * fix(ui): catch in-place message id mutations and react to layout shifts Follow-ups from deep review: - MutationObserver on .message-render now also watches the id attribute. During the SSE lifecycle a single DOM node's id cycles through three values (client UUID -> createdHandler id -> server id, see the comment in MultiMessage.tsx), which meant the previous childList-only observer never refreshed entries after a streaming response. Nav clicks on the most recent message were silently failing because getElementById returned null for the stale id. - ResizeObserver now calls scheduleTick() instead of only flipping a flag. The flag was only consumed inside the scroll handler's tick, so heights that changed while the user wasn't scrolling (assistant message streaming in, code blocks highlighting) left offsetsTop/offsetsBottom stale and canGoUp / canGoDown wrong. Both handlers now route through scheduleTick so a resize and a scroll share the same rAF slot. - Unify scroll and resize callbacks on scheduleTick. Removes a duplicate rAF path and makes the effect cleaner. - Single-pass build of newIds during incremental IO sync (previously entries.map().new Set() did two passes for no reason). - CSSTransition timeouts drop from 550/700 to 300/250 to match the new scroll-to-bottom animations. Old values left the button in the DOM for up to 450ms after the exit animation finished. - ScrollToBottom.tsx imports reordered to longest-first per project convention. - style.css: collapse split `border: 1px solid` + `border-color` into one shorthand; dark variant still overrides border-color cleanly. - Tests: add SSE-lifecycle test that mutates a .message-render id in place and asserts the nav now shows an indicator for the new id and none for the old one. HoverCard mock no longer spreads unknown props to the DOM div (drops a React warning). * fix(ui): address deep-review follow-ups on MessageNav - Move activeScrollToken from module scope to a per-instance useRef (scrollTokenRef). When LibreChat eventually mounts more than one MessageNav side-by-side (multi-panel / added-convo view) a click in one panel will no longer cancel an in-flight smooth scroll in another. scrollToMessageStart is now an instance useCallback and the button click path goes through an onSelect prop on MessageIndicator, keeping the memoized indicator stable. - messagesById goes through a ref (messagesByIdRef) so refreshEntries is no longer recreated on every streaming token. Previously messagesById landed in both the useMemo and the refreshEntries dep array, so each streaming response rebuilt the MutationObserver effect dozens of times per second. A separate small effect still calls refreshEntries when messagesById changes, so previews stay fresh. - Extract USER_TURN_SELECTOR constant and tighten the text-preview type narrowing so we no longer need the `as { value?: string }` cast (TS narrows string | TextData correctly through the `typeof object` + property access guard). - Cache the computed scroll margin (4rem = 64px) in scrollMarginRef so the nav callbacks don't call getComputedStyle on every click. - Tests: add a two-instance isolation test that verifies scroll tokens don't cross between mounted MessageNavs. Drop the unused `import React from 'react'` pattern in favor of local type aliases. - client/package.json: bump @babel/preset-typescript to ^7.28.5. The old ^7.22.15 constraint was resolving to 7.23.3 via hoisting, which can't parse modern `import type` syntax on a clean install and was breaking the test suite. * fix(ui): address re-review — clean lockfile + ScrollToBottom ref target - package-lock.json: the preset-typescript bump last commit pulled in transitive Babel packages resolved through a local internal registry (npm.internal.berry13.com). Rewrote those 31 entries back to the public npmjs.org registry so CI and contributors can install cleanly. Integrity hashes unchanged — content-addressed. - ScrollToBottom now forwards its ref to the wrapping <div> instead of the inner <button>. CSSTransition's nodeRef + unmountOnExit can now add transition classes to the actual root element, so the layout wrapper is what mounts/unmounts, not just the button. Updated scrollToBottomRef type in MessagesView to HTMLDivElement. - jumpToPrevious / jumpToNext skip the document.getElementById fallback lookup when scrollMarginRef is already populated, which is the normal case after the first scroll-tick effect run. * fix(ui): preserve IntersectionObserver across in-place id mutations The IO sync effect was observing new ids before unobserving old ones. During the SSE lifecycle of a fresh chat, a single .message-render node cycles through three ids (client UUID -> handler id -> server id). When the id mutated on the same element, the effect would call observe(el) then unobserve(el) on that element in the same pass — leaving it permanently unobserved. The active-message highlight never updated for the new id until a hard refresh rebuilt everything from scratch. Switched to element-identity tracking. Build an element -> newId map from entries, then for each currently observed [oldId, el]: - if the element no longer appears in entries, unobserve and drop it - if the element appears under a new id, migrate observed and visibleSet keys in place — the IntersectionObserver keeps watching the same DOM node uninterrupted Genuinely new elements get observed afterward as before. Rename doesn't fire an IO callback, so flush activeIds manually when at least one migration happened. Existing convos already had this working because their ids never mutate after load — only fresh chats hit the SSE id cycle, which matches the reproduction. * fix(ui): keep message nav current and pinned at bottom
* feat: add signed CloudFront downloads * fix: preserve local IdP avatar paths * fix: address signed download review findings * fix: harden CloudFront cookie scope validation * fix: preserve URL save API compatibility * fix: store CDN SSO avatars under shared prefix * fix: Harden CloudFront tenant file access * fix: Preserve CloudFront download compatibility * fix: Address CloudFront review follow-ups * fix: Preserve file URL fallback user paths * fix: Address download review hardening * fix: Use file owner for S3 RAG cleanup * fix: Address final download review nits * fix: Clear stale avatar CloudFront cookies * fix: Align download filename helpers with dev * fix: Address final CloudFront review follow-ups * fix: Stream S3 URL uploads * fix: Set S3 stream upload length * fix: Preserve download metadata filepath * fix: Avoid remote content length for stream uploads * fix: Use bounded multipart URL uploads * fix: Harden S3 filename boundaries
* fix: harden agent file access * style: format agent file query * fix: prune agent file refs on alternate writes * test: fix agent pruning specs
…12983) * 🌐 fix: Percent-encode X-File-Metadata header for Unicode filenames After #12977 preserved Unicode in filenames, the download route crashes with ERR_INVALID_CHAR because JSON.stringify(file) now contains non-ASCII characters that Node.js rejects in HTTP headers per RFC 7230. Wrap the header value in encodeURIComponent on the server and decodeURIComponent on the client before JSON.parse. * fix: Update file route tests after dev merge --------- Co-authored-by: Danny Avila <danny@librechat.ai>
* fix: Align auto-refill next date * style: Fix auto-refill lint formatting * refactor: Share auto-refill eligibility date * refactor: Consolidate refill interval units * fix: Guard malformed refill interval units * fix: Preserve refill unit fallback label
* fix: Improve subagent dialog prompt rendering * fix: Preserve cancelled subagent traces * chore: Reuse generic prompt toggle labels * fix: Scope new-chat subagent cleanup exemption * fix: Use valid subagent prompt min-height * fix: Flatten subagent dialog conditionals * fix: Place subagent prompt in dialog scroll
* feat(files): add optional region-aware storage keys * test(files): fix region storage CI fixtures * feat(files): finalize inline CloudFront asset namespaces * fix(files): allow wildcard region CloudFront cookies * fix(files): preserve legacy storage key compatibility * fix(files): align CloudFront clear cookie cleanup * fix(files): clear legacy CloudFront cookie scopes * chore(files): clean up storage review nits * fix(files): keep inline namespaces CloudFront-only
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )