fix: preserve links and mentions in Slack lists (#10447)

This commit is contained in:
Wei Chengqian
2026-10-09 12:37:53 +08:00
committed by GitHub
parent d8ef9dd3b0
commit 5994167942
2 changed files with 82 additions and 7 deletions
@@ -297,15 +297,25 @@ class SlackAdapter(Platform):
list_text = ""
for item in list_items:
if item.get("type") == "rich_text_section":
item_elements = item.get("elements", [])
item_text = ""
for item_element in item_elements:
if item_element.get("type") == "text":
item_text += item_element.get("text", "")
list_text += f"• {item_text}\n"
# Reuse section parsing to preserve inline components.
item_components = self._parse_blocks(
[{"type": "rich_text", "elements": [item]}]
)
list_text += "• "
for component in item_components:
if isinstance(component, Plain):
list_text += component.text
else:
if list_text:
message_components.append(
Plain(text=list_text)
)
list_text = ""
message_components.append(component)
list_text += "\n"
if list_text.strip():
message_components.append(Plain(text=list_text.strip()))
message_components.append(Plain(text=list_text.rstrip()))
elif block_type == "section":
# 处理段落块
+65
View File
@@ -115,3 +115,68 @@ def test_slack_quote_keeps_boundaries_around_mentions(before_mention, after_ment
f"Question:\n{before_mention}{after_mention}\nNext paragraph"
)
assert [c.qq for c in components if isinstance(c, At)] == ["UOTHER"]
@pytest.mark.asyncio
@pytest.mark.parametrize("style", ["bullet", "ordered"])
async def test_slack_list_preserves_links_and_mentions(style):
adapter = SlackAdapter(
make_platform_config("slack", bot_token="xoxb-test", app_token="xapp-test"),
{},
asyncio.Queue(),
)
adapter.bot_self_id = "UBOT"
adapter.web_client.users_info = AsyncMock(
return_value={"user": {"real_name": "Tester"}},
)
adapter.web_client.conversations_info = AsyncMock(
return_value={"channel": {"is_im": False, "name": "test"}},
)
url = "https://example.com/slack-list-8642"
received = await adapter.convert_message(
{
"user": "UTEST",
"channel": "CTEST",
"text": f"<@UBOT> Link: {url}",
"blocks": [
{
"type": "rich_text",
"elements": [
{
"type": "rich_text_list",
"style": style,
"elements": [
{
"type": "rich_text_section",
"elements": [
{"type": "user", "user_id": "UBOT"},
{"type": "text", "text": " Link: "},
{"type": "link", "url": url, "text": "Probe"},
{"type": "text", "text": " after"},
],
},
{
"type": "rich_text_section",
"elements": [{"type": "link", "url": url}],
},
{
"type": "rich_text_section",
"elements": [{"type": "user", "user_id": "UOTHER"}],
},
{
"type": "rich_text_section",
"elements": [{"type": "text", "text": "End"}],
},
],
},
],
},
],
},
)
assert [c.qq for c in received.message if isinstance(c, At)] == ["UBOT", "UOTHER"]
assert received.message_str == (
f"• Link: [Probe]({url}) after\n• [{url}]({url})\n• \n• End"
)
assert [type(c) for c in received.message] == [Plain, At, Plain, At, Plain]