From d38d2a8f0ae1fd50ea72c7890b606d0ff9fc4389 Mon Sep 17 00:00:00 2001 From: Phantomthedog Date: Thu, 24 Sep 2026 18:59:40 -0500 Subject: [PATCH] fix(desktop): keep a bare URL's full text visible in chat markdown (#121007) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MarkdownLink nulled fallbackLabel whenever the link text matched the target URL — exactly the bare-autolink case — so PrettyLink fell through to urlSlugTitleLabel and rendered a host-only label (`ncpssd.org` for https://www.ncpssd.org/), with the address readable only via hover/inspect. The user could not read an address sent in chat. The link's own text is always a legitimate fallback label; pass it through. Labeled links are unchanged: their authored label already wins display, and that shape (a label hiding the address) is PrettyLink's documented contract, not a bug. Salvaged from PR #38213 by Phantomthedog (the fallbackLabel change and the localhost/example.com render tests), reworked to keep the change scoped to the bare-autolink shape and reshaped into an end-to-end MarkdownTextContent test alongside the existing session/filelinks suites. --- .../markdown-text.bare-url.test.tsx | 40 +++++++++++++++++++ .../components/assistant-ui/markdown-text.tsx | 9 ++++- 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 apps/desktop/src/components/assistant-ui/markdown-text.bare-url.test.tsx diff --git a/apps/desktop/src/components/assistant-ui/markdown-text.bare-url.test.tsx b/apps/desktop/src/components/assistant-ui/markdown-text.bare-url.test.tsx new file mode 100644 index 0000000000..ac11a4813b --- /dev/null +++ b/apps/desktop/src/components/assistant-ui/markdown-text.bare-url.test.tsx @@ -0,0 +1,40 @@ +import { cleanup, render, screen } from '@testing-library/react' +import { afterEach, describe, expect, it } from 'vitest' + +import { MarkdownTextContent } from './markdown-text' + +afterEach(() => cleanup()) + +// End-to-end for the bare-autolink shape of #121007: a bare URL an agent sent +// must render with its full text visible — PrettyLink used to collapse it to a +// host-only label (`ncpssd.org`) with the address readable only via hover. +// Labeled links keep their authored label (that hiding is intended design). +describe('MarkdownTextContent bare URLs', () => { + it('shows the full URL text for a bare autolink', () => { + render() + + const link = screen.getByRole('link') as HTMLAnchorElement + + expect(link.getAttribute('href')).toBe('https://www.ncpssd.org/') + expect(link.textContent).toContain('https://www.ncpssd.org/') + }) + + it('does not collapse a host-only URL to a bare hostname', () => { + render() + + const link = screen.getByRole('link') as HTMLAnchorElement + + // urlSlugTitleLabel would render `example.com`; the full URL is the label. + expect(link.textContent).toContain('https://example.com/') + }) + + it('keeps the authored label for a labeled markdown link', () => { + render() + + const link = screen.getByRole('link') as HTMLAnchorElement + + expect(link.getAttribute('href')).toBe('https://www.ncpssd.org/') + expect(link.textContent).toContain('the database') + expect(link.textContent).not.toContain('ncpssd.org/') + }) +}) diff --git a/apps/desktop/src/components/assistant-ui/markdown-text.tsx b/apps/desktop/src/components/assistant-ui/markdown-text.tsx index f14b3d78ee..2a4b3441ba 100644 --- a/apps/desktop/src/components/assistant-ui/markdown-text.tsx +++ b/apps/desktop/src/components/assistant-ui/markdown-text.tsx @@ -345,7 +345,14 @@ function MarkdownLink({ children, className, href, ...props }: ComponentProps<'a } } - const fallbackLabel = text && normalizeExternalUrl(text) !== target ? text : undefined + // Always pass the link's own text as the fallback label so a bare URL stays + // fully visible (#121007): previously this was `undefined` when the child + // text matched the target URL (the bare-autolink case), so PrettyLink fell + // through to urlSlugTitleLabel — a host-only label like `ncpssd.org` with + // the address readable only via hover/inspect. The full URL is the label the + // sender actually wrote into the chat. Labeled links are unchanged: their + // authored label already wins display by design. + const fallbackLabel = text || undefined return (