ποΈ fix: Stack Slide Previews and Show File Cards on Every Message - #16496
Open
TomasPalsson wants to merge 25 commits into
Open
TomasPalsson wants to merge 25 commits into
TomasPalsson wants to merge 25 commits into
Conversation
β¦version Two cards for the same file across different messages now both render instead of one message winning the only visible chip. Registration into the artifact panel now compares update timestamps (falling back to a mount-order tie-break) so an older card mounting after a newer one, or remounting after the newer card unmounts, can never clobber the newer content. Search and shared conversation views now scope every rendered part to its own message so the same fix applies there.
Extends the JSDOM pptx bootstrap harness with an options object (native aspect ratio, renderer install/behavior, a capturable 8s safety-net timer, and a mutable render-slot width) so it can drive every panel width, a 30-slide deck with no inner scroll box, a resize-triggered refit, both 16:9 and 4:3 decks, and each fallback trigger (renderer missing, renderer throws, empty slide list, empty slide wrappers, render timeout). Clears the pptx-preview library's own inline width/background once slides are wrapped, since JSDOM's getComputedStyle doesn't apply the existing stylesheet's !important override the way a real browser does, and restores the 16px spacing between stacked slide blocks now that they live inside the library's own wrapper box instead of directly under #lc-render.
β¦sage A message that ran a tool twice on the same output file (e.g. rewriting data.zip) showed a card for every run. mapAttachments now collapses attachments that share a file identity to their last occurrence before grouping by tool call, so a repeated file surfaces once, under its newest run. Non-file attachments (no file_id or filepath) are untouched.
A code-execution diagram rewritten in a later turn now shows a card on every message holding that file, but opening an older message's card still displayed the stale content. Each ToolMermaidArtifact now offers its version to a shared per-file "newest seen" record on mount, and hands the newest entry to Mermaid for registration while keeping its own inline render unchanged. Corrects two comments claiming shared conversation views mount with no message context, which Share/Message already provides.
β¦ copy over a later unlinked duplicate, and key id-less files by filepath instead of filename
β¦ of the message pipeline Two id-less attachments that share a display name but live at different filepaths no longer collapse into one chip in the folded attachment group.
β¦med files each keep their own card
TomasPalsson
marked this pull request as ready for review
September 29, 2026 11:23
TomasPalsson
added a commit
to aproorg/LibreChat
that referenced
this pull request
Sep 29, 2026
β¦breChat-AI#16496) - Wrap and scale each pptx slide on its own at panel width, init pptx-preview with a width only, pin each slide to its block on wide panels, space the slides, guard finalize against running twice, and reserve the scrollbar gutter so the panel scrolls to the last slide without flicker. - Scope file card dedup to the message and register panel content only when newer by lastUpdateTime (global latest-mount claim kept as the equal-time tie-break), so every message that made a file shows its card and every card opens the newest version; diagram cards and search results follow the same rule. - Keep one copy per file per message (the newest write, tool-call-linked entries only), dedup the folded file group with the same identity, and key id-less files by path before name.
8 of 9 tasks
Contributor
Author
|
@codex review |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When an agent's code run makes a PowerPoint deck, the side panel squeezes the whole deck into one box scaled as if it were a single slide: only slide 1 shows and the panel can't scroll to the rest.
wrapSlides()in the pptx preview bootstrap walkedcontainer.children, butpptx-preview@1.0.7nests every.pptx-preview-slide-wrapperinside one.pptx-preview-wrapper, so the whole deck was wrapped and scaled as one "slide".initalso got a fixedheight, which turned that box into its own scroll region.Separately, when an agent remakes a file under the same name in a later turn (same
file_id), its card showed on only one message in the whole chat, because card dedup claimedtoolArtifactClaim(fileId)globally and the last card to mount won. A file written by two code runs in one message could also show twice.Changes
packages/api/src/files/documents/html.ts:pptxPreview.initgets a width only. Each.pptx-preview-slide-wrapperis wrapped and scaled on its own, inserted viaslide.parentNode, and its inlinemargin: 0 autois cleared so panels wider than 992px don't shift and clip it. The library's wrapper box follows the content width on a transparent background, slides get 16px spacing,finalize()can't run twice, andhtml { scrollbar-gutter: stable }stops the refit flicker with space-taking scrollbars. The fallbacks (library missing, throws, empty render, 8s timeout) are unchanged.Parts/claim.ts(new):useToolArtifactClaimscopes the card claim to${messageId}::${id}(the bare id when there's no message), shared byToolArtifactCardandToolMermaidArtifact.Parts/ToolArtifactCard.tsx: registers panel content only when its version is newer bylastUpdateTime; the old global latest-mount claim is kept only as the equal-time tie-break, so every card opens the newest version.Parts/ToolMermaidArtifact.tsx,Mermaid/Mermaid.tsx: diagram cards offer their version to a per-file Jotai atom and register the newest one when opened, while the inline diagram keeps showing its own message's source.registerArtifactnever overwrites a strictly newer entry.SearchContent.tsx: passes the row'smessageIdto every part, so search results place cards per message too.utils/map.ts:mapAttachmentskeeps one copy per file per message (the newest write; only tool-call-linked entries compete).FileAttachmentGroupuses the samefileIdentity.utils/artifacts.ts:toolArtifactKeyfalls backfile_id β filepath β filename(wasfile_id β filename β filepath), so two different id-less download-fallback files with the same name no longer collapse into one card.No server, schema or config changes beyond the preview HTML, and no new script sources or CSP entries. Previews stored before this keep their old HTML until the deck is remade.
Type of change
Testing
packages/api/src/files/documents/layout.spec.tsruns the real bootstrap in JSDOM against a fakepptxPreviewthat mirrors the library's DOM and inline styles: one block per slide at 360/768/1480px, 30 slides with no inner scroll box, resize refit, 16:9 and 4:3 ratios, every fallback mode, spacing, wide-panel pinning, scrollbar gutter.npx jest src/files/documentsβ 220 passing.Parts/__tests__/ToolArtifactCard.test.tsxandParts/__tests__/FileAttachmentGroup.test.tsx, plus new cases inutils/__tests__/map.test.tsandutils/__tests__/artifacts.test.ts.npx jest src/components/Chat/Messages/Content src/components/Messages/Content/Mermaid src/components/Artifacts src/hooks/Artifacts src/hooks/Files src/utils/__tests__/map.test.ts src/utils/__tests__/artifacts.test.tsβ 1977 passing. The existingArtifactRouting.test.tsxno-message cases are unchanged.pptxToHtmlwith the pinnedpptx-preview@1.0.7, at 360β1480px and live resize: one block per slide, width = panel β 32px, 0px sideways overflow, last slide reachable.report.pptxshows a card on both turns and the turn-1 card opens the newest deck; a remade.mmdopens its newest version from the older message; a file written by two runs in one message shows once; the panel scrolls to the last slide at narrow and expanded widths.npx tsc --noEmitclean onpackages/apiandclient;npm run static-checksclean on the changed files.Test Configuration
Checklist