diff --git a/src/langbot/pkg/platform/sources/dingtalk.py b/src/langbot/pkg/platform/sources/dingtalk.py
index 2a31a1161..6aad0bde0 100644
--- a/src/langbot/pkg/platform/sources/dingtalk.py
+++ b/src/langbot/pkg/platform/sources/dingtalk.py
@@ -577,12 +577,16 @@ class DingTalkAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter):
prior = self.active_turn_text.get(session_key, '') if session_key else ''
if prior.strip():
parts.append(prior.rstrip())
- parts.append('---')
+ parts.append('
')
+ # DingTalk's card markdown widget strips `\n\n` paragraph breaks in
+ # template content slots, fusing inline siblings into a single line.
+ # Force visual line breaks with explicit HTML `
` tags so the
+ # title sits on its own line above form_content.
if node_title:
parts.append(f'**{node_title}**')
if form_content:
parts.append(form_content)
- display_content = '\n\n'.join(parts) or '请选择一个操作以继续。'
+ display_content = '
'.join(parts) or '请选择一个操作以继续。'
try:
await self.bot.update_card_data(
@@ -666,7 +670,7 @@ class DingTalkAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter):
parts.append(f'**{node_title}**')
if form_content:
parts.append(form_content)
- display_content = '\n\n'.join(parts) or '请选择一个操作以继续。'
+ display_content = '
'.join(parts) or '请选择一个操作以继续。'
btns = []
for idx, action in enumerate(actions):
@@ -980,8 +984,8 @@ class DingTalkAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter):
parts.append(f'**{node_title}**')
if form_content:
parts.append(form_content)
- parts.append(f'---\n✅ 已选择:**{action_title}**')
- content = '\n\n'.join(parts)
+ parts.append(f'
✅ 已选择:**{action_title}**')
+ content = '
'.join(parts)
if self.ap is not None:
self.ap.logger.info(f'DingTalk _mark_card_resolved: out_track_id={out_track_id} action={action_title!r}')
try: