Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions apps/desktop/src/components/assistant-ui/markdown-text.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,33 @@ describe('preprocessMarkdown', () => {
'<https://www.getyourguide.com/en-gb/san-juan-puerto-rico-l355/san-juan-old-san-juan-sunset-cruise-with-drinks-transfer-t405191/>'
)
})

it('does not swallow trailing emphasis asterisks into an autolinked url', () => {
const input = '**PR opened: https://github.com/NousResearch/hermes-agent/pull/12345**'

const output = preprocessMarkdown(input)

// The URL is autolinked WITHOUT the trailing `**` glued into the href,
// and the bold emphasis run stays intact so it renders as bold + a link.
expect(output).toContain('<https://github.com/NousResearch/hermes-agent/pull/12345>')
expect(output).not.toContain('pull/12345**>')
expect(output).not.toContain('12345*')
})

it('stops an autolinked url at mid-string bold markers', () => {
const input = 'See https://github.com/foo/bar**bold** for details.'

const output = preprocessMarkdown(input)

expect(output).toContain('<https://github.com/foo/bar>')
expect(output).toContain('**bold**')
})

it('keeps underscores and tildes inside autolinked url paths', () => {
const input = 'Docs at https://example.com/a_b/c~d/page'

const output = preprocessMarkdown(input)

expect(output).toContain('<https://example.com/a_b/c~d/page>')
})
})
9 changes: 8 additions & 1 deletion apps/desktop/src/lib/markdown-preprocess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@ const FENCE_LINE_RE = /^([ \t]*)(`{3,}|~{3,})([^\n]*)$/
const EMPTY_FENCE_BLOCK_RE = /(^|\n)[ \t]*(?:`{3,}|~{3,})[^\n]*\n[ \t]*(?:`{3,}|~{3,})[ \t]*(?=\n|$)/g
const CODE_FENCE_SPLIT_RE = /((?:```|~~~)[\s\S]*?(?:```|~~~))/g
const INLINE_CODE_SPLIT_RE = /(`[^`\n]+`)/g
const RAW_URL_RE = /https?:\/\/[^\s<>"'`]+[^\s<>"'`.,;:!?]/g
// Bare-URL autolink matcher. The character classes EXCLUDE `*` so a URL that
// abuts markdown emphasis with no separating space (e.g. `**label: https://x**`,
// a very common LLM pattern) doesn't swallow the trailing `**` into the href.
// `*` is never meaningful in a real URL path, and GFM's own autolink extension
// likewise strips trailing emphasis/punctuation — so dropping it here is safe
// and keeps the emphasis run intact. Other trailing punctuation is still peeled
// off by the final `[^\s<>"'`*.,;:!?]` class.
const RAW_URL_RE = /https?:\/\/[^\s<>"'`*]+[^\s<>"'`*.,;:!?]/g
const LOCAL_PREVIEW_URL_RE = /(^|\s)https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1\])(?::\d+)?\/?[^\s<>"'`]*/gi
const LOCAL_PREVIEW_ONLY_RE = /^https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1\])(?::\d+)?\/?$/i
const URL_ONLY_LINE_RE = /^\s*https?:\/\/\S+\s*$/i
Expand Down
Loading