Skip to content

fix(slack): Preserve hyperlink URLs in assistant context#156

Draft
dcramer wants to merge 3 commits intomainfrom
dcramer/fix/preserve-slack-hyperlinks
Draft

fix(slack): Preserve hyperlink URLs in assistant context#156
dcramer wants to merge 3 commits intomainfrom
dcramer/fix/preserve-slack-hyperlinks

Conversation

@dcramer
Copy link
Copy Markdown
Member

@dcramer dcramer commented Apr 5, 2026

When a user sends a message with Slack hyperlinks (<url|display text>), the URLs are stripped before reaching the model. The adapter's extractPlainText() converts the AST to plain text, discarding link URLs entirely — the assistant only sees the display text with no knowledge of embedded URLs (e.g., PR links, thread links).

This switches from message.text (plain text) to message.formatted (the AST) and walks the tree with a new extractTextPreservingLinks() helper that renders links as [text](url) while keeping all other content as unescaped plain text. This preserves URLs for the model without introducing markdown escape artifacts like \_.

Three ingress points updated:

  • slack-runtime.ts — subscribed message handler
  • reply-executor.ts — direct mention handler
  • conversation-memory.ts — thread backfill

Also updates stripLeadingBotMention to handle the @USER_ID format produced by the AST — the existing <@USER_ID> regex was dead code since the adapter's toAst() already strips angle brackets from mention tokens.

Fixes #137

When a user sends a message with Slack hyperlinks (<url|display text>),
the URLs were stripped before reaching the model. The adapter's
extractPlainText() converts the AST to plain text, discarding link URLs
entirely. The assistant only saw the display text with no knowledge of
embedded URLs.

Use message.formatted (the AST) instead of message.text, and walk
the tree with a new extractTextPreservingLinks() helper that renders
links as [text](url) while keeping all other content as plain text.

Also update stripLeadingBotMention to handle the @USER_ID format
produced by the AST (the existing <@USER_ID> regex was dead code since
the adapter's toAst already strips angle brackets).

Fixes #137

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
junior-docs Ready Ready Preview, Comment Apr 5, 2026 9:33pm

Request Review

visitNode only handled 'text' type nodes for reading node.value.
mdast inlineCode and code nodes also store content in value (not in
children), so backtick-wrapped content was silently dropped.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add newline separators for block-level AST containers (list,
listItem, blockquote, etc.) so bulleted lists and similar structures
are not concatenated without whitespace.

Remove the dead <@USER_ID> regex in stripLeadingBotMention — the AST
never produces angle-bracket mentions, and chaining it with the new
@USER_ID regex risked double-stripping.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b73c604. Configure here.

"listItem",
"blockquote",
"heading",
]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Paragraph in BLOCK_TYPES inserts newlines between inline elements

High Severity

paragraph and heading are included in BLOCK_TYPES, which causes their inline children (text, links, emphasis, etc.) to be joined with "\n" instead of "". In a standard markdown AST, paragraphs contain inline children — the paragraph itself is a block element, but its children are not. A message like "check [this PR](url) please" produces "check \n[this PR](url)\n please" with spurious newlines splitting a single sentence. The existing tests don't catch this because they use toContain rather than exact matching. This directly impacts the core goal of the PR — every message with a hyperlink or any inline formatting will have corrupted text sent to the model.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit b73c604. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Slack message hyperlinks stripped before reaching assistant context

1 participant