LibreChat/client/src/store
Marco Beretta f174da6159
📋 feat: Copy Messages as Rich Text (#15087)
* feat: copy messages as rich text

Adds an opt-in setting that places a rendered HTML flavor on the
clipboard next to the markdown, so pasting an assistant response into an
app that does not understand Markdown (Teams, Outlook, Word) keeps its
headings, lists, tables and code formatting.

The HTML is serialized from the same mdast pipeline the message renderer
already uses, with inline styles because those paste targets strip
stylesheets. Raw HTML in a message is escaped rather than passed
through, matching the renderer, and link and image URLs go through the
existing isSafeUrl allowlist.

The plain copies (share links, API keys, OAuth callback URLs) keep using
the base hook, so they are never wrapped in markup. The setting is off by
default: markdown-aware targets prefer the HTML flavor when it is
present, so making it unconditional would regress them.

Closes #13973

* fix: address review feedback on rich text clipboard copy

Mirror the renderer's `singleDollarTextMath: false` so paired currency
such as "$5 to $10" is not read as math and stripped of its dollar
signs in the HTML flavor.

Pair every background the serializer sets with its own foreground, and
let blockquotes and table cells inherit the destination's colors. The
paste target's theme is unknowable, so a lone light background could
land under a dark editor's light text.

Resolve reference-style links and images against their definitions
rather than dropping the hyperlink.

Skip the HTML flavor for user messages while `enableUserMsgMarkdown` is
off. Those render as literal text on screen, so formatting them on paste
would not match what was copied.

* fix: mirror the message renderers more closely in rich text copies

Apply the same `remarkApproxTilde` and `remark-supersub` transforms the
renderers apply to the parsed tree, so `x^2^` arrives as a superscript
instead of literal markers.

Select the renderer to mirror per message: `Markdown` (assistant) enables
directives, `MarkdownLite` (user) does not, so a user message showing
literal `:::` markers keeps them in the HTML flavor.

Resolve path-relative URLs against the app's base URI. A generated file
or image link resolves against LibreChat on screen but against the
destination document once pasted. Absolute URLs are passed through
verbatim rather than normalized.

Serialize each text content part as its own document. Each part renders
through its own Markdown instance on screen, so a construct must not span
two of them; a private-use sentinel carries the boundary through citation
processing, which only touches its own markers.

* fix: match the renderer on line breaks, relative URLs and LaTeX

Message text renders under white-space: pre-wrap, so a soft line break is
a visible line on screen. Emit those as <br /> instead of a raw newline,
which every HTML paste target would collapse to a space.

Screen URLs through react-markdown's own transform rather than the
artifact template's isSafeUrl, which rejected bare relative targets like
docs/guide.html and dropped links the conversation shows as working.
Everything relative is then resolved against the app's base URI.

Apply preprocessLaTeX to assistant segments when LaTeXParsing is on, as
the assistant renderer does, so single-dollar math is read as math rather
than left as literal dollar signs.

* fix: align rich text copies with directives, footnotes and search rendering

Show an inline directive by name, as the artifact plugin displays it,
rather than dropping the marker and keeping only its children.

Number footnotes by the order their references appear and omit a
definition nothing references, matching what the renderer displays
instead of emitting the source label.

Keep a generated citation marker from resolving against a reference
definition that happens to share its number, which linked the citation to
the wrong URL. An unresolved reference now falls back to its own source
form, as remark-rehype reverts one.

Let a caller state the renderer its row was displayed with. SearchContent
falls back to MarkdownLite for a message without content parts whatever
its author, so search results and shared links pass that through.

Replace the part-boundary sentinel with a citation processor that carries
its numbering across parts, so each part is formatted on its own without
a private-use character that message text could itself contain.

* fix: close remaining gaps between rich text copies and the rendered message

Route rooted /images/ sources through apiBaseUrl the way the renderer's
image component does, so a subdirectory deployment's images survive the
paste instead of losing the base path to the leading slash.

Show an artifact directive by its title, which is what its button
displays, rather than pasting the implementation the conversation hides.

Gather footnote definitions into a footer ordered by first reference,
matching where and in what order the renderer shows them.

Keep a loose list's paragraph wrappers. mdast records looseness on the
list, not on every item, so the parent decides whether an item is tight.

Emit the citation footer as its own segment. Appended to a segment ending
in an unclosed fence, the sources were swallowed into the code block.

Pass the search results MessageParts already loads into useMessageHelpers,
which was copying assistant responses with their citation markers stripped
and no sources appended.

* fix: transform MCP markers and default an untitled artifact

Run mcpUIResourcePlugin over assistant segments as the full renderer
does, so a UI resource marker leaves as nothing rather than pasting the
protocol text. An embedded interactive resource has no static form, and
MarkdownLite does not transform the markers, so user turns keep them
literal exactly as they are displayed.

Fall back to the Artifact component's own default title when a directive
carries none, instead of dropping the artifact from the copy.

* fix: honor definition precedence, file link rewrites and error rows

Keep the first of two reference definitions sharing a label, as
CommonMark does, instead of letting the last one win.

Route a user's own generated-file links through the app's file endpoint
the way the anchor component does, so a pasted link points where the one
in the conversation points rather than at the provider URL.

Skip the HTML flavor for an errored row. ErrorMessage renders those, so
serializing the raw payload as markdown would paste something the
conversation never showed.

Scope reserved citation labels to the segment that generated them. Each
part is its own document, so a legitimate reference in one part is no
longer suppressed by a citation numbered the same in another.

* fix: resolve file citations against the references collection

File-search sources live under references, as useCitation reads them,
but the clipboard's type map had no entry for file. Their markers were
therefore stripped without a source, so a citation visible in the
response went missing from the copy.
2026-09-05 13:36:07 +02:00
..
__tests__ 🔙 fix: Stop Stacking History Entries on New-Chat Param Changes (#14891) 2026-08-16 11:05:07 -04:00
agents.ts 📌 fix: Preserve Ephemeral Agent Selections on Optimistic Hydration (#13433) 2026-05-31 16:32:45 -04:00
artifacts.ts 🚀 feat: Decouple File Attachment Persistence from Preview Rendering (#12957) 2026-05-06 03:04:19 -04:00
autoScroll.ts 🪂 fix: Land Navigation Auto-Scroll on the Rendered Thread (#15014) 2026-08-19 14:23:08 -04:00
clockFormat.ts 🕰️ feat: Clock Format and Week Start Preferences (#15121) 2026-08-23 18:41:14 -04:00
endpoints.ts
families.ts 🪶 feat: Enable Standalone Skill Authoring (#15480) 2026-09-01 18:39:05 -04:00
favorites.ts
fontSize.ts
index.ts 🔌 refactor: Give the Subagent Surface a Host Seam and Its Own Jotai State (#15455) 2026-09-01 11:15:42 -04:00
jotai-utils.ts
language.ts ⚙️ refactor: Lazy load locale resources (#13640) 2026-06-10 08:48:58 -04:00
mcp.ts 🃏 fix: Attach Request-Scoped MCP Servers From the Builder via the mcp_all Wildcard (#14177) 2026-07-12 08:10:01 -04:00
misc.ts 🎛️ feat: Consistent Dialogs, Clearer Settings, and a Keyboard Shortcuts Switch (#14882) 2026-08-16 16:10:17 -04:00
preset.ts
prompts.ts
ptc.ts 🖥️ feat: Stream PTC Inner Tool Calls as a CLI-Style Trace (#15115) 2026-08-23 01:18:14 -04:00
sandbox.ts ♨️ feat: Prewarm Stateful Code Sandboxes with Cold-Boot UX Feedback (#14239) 2026-07-14 10:25:37 -04:00
search.ts
settings.ts 📋 feat: Copy Messages as Rich Text (#15087) 2026-09-05 13:36:07 +02:00
showThinking.ts
smoothStreaming.ts 🚣‍♀️ feat: Smooth Streaming Text Fade-In (#14757) 2026-08-12 13:21:52 -04:00
steer.ts ⚡ feat: Reliable Interrupt & Steer Escalation and Recovery (#14558) 2026-07-31 20:07:56 -04:00
submission.ts
temporary.ts
text.ts
toast.ts
usage.spec.ts 🪟 feat: Faithful Over-Window Context Estimate via Prune Mirror and Overhead Reserve (#13959) 2026-06-25 17:12:53 -04:00
usage.ts 🎨 feat: Color the Context Gauge by Category and Collapse its Breakdown (#14855) 2026-08-14 22:46:10 -04:00
user.ts
utils.ts 📱 feat: Give the Mobile Nav the Whole Screen (#14849) 2026-08-16 08:29:25 -04:00
weekStart.ts 🕰️ feat: Clock Format and Week Start Preferences (#15121) 2026-08-23 18:41:14 -04:00