feat(web): Add markdown rendering support to pipeline chat messages with toggle (#1826)

* Initial plan

* Add markdown rendering support to pipeline debug dialog messages with toggle button

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>

* Fix code review feedback: remove conflicting styles and imports

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>

* perf: styles

* fix: websocket message broadcasting cross-contamination between person and group channels

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>
Co-authored-by: Junyan Qin <rockchinq@gmail.com>
This commit is contained in:
Copilot
2025-12-01 13:44:01 +08:00
committed by GitHub
parent 16ae8ac546
commit b634aa48dc
12 changed files with 258 additions and 53 deletions

View File

@@ -117,7 +117,7 @@ class WebSocketAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter)
# 从message_source获取pipeline_uuid和connection_id
pipeline_uuid = self.ap.platform_mgr.websocket_proxy_bot.bot_entity.use_pipeline_uuid
# session_type = 'group' if isinstance(message_source, platform_events.GroupMessage) else 'person'
session_type = 'group' if isinstance(message_source, platform_events.GroupMessage) else 'person'
# 生成新的消息ID
msg_id = len(session.get_message_list(pipeline_uuid)) + 1
@@ -134,13 +134,15 @@ class WebSocketAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter)
# 保存到历史记录
session.get_message_list(pipeline_uuid).append(message_data)
# 直接广播到所有该pipeline的连接
# 直接广播到所有该pipeline的连接包含session_type信息
await ws_connection_manager.broadcast_to_pipeline(
pipeline_uuid,
{
'type': 'response',
'session_type': session_type,
'data': message_data.model_dump(),
},
session_type=session_type,
)
return message_data.model_dump()
@@ -162,6 +164,7 @@ class WebSocketAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter)
)
pipeline_uuid = self.ap.platform_mgr.websocket_proxy_bot.bot_entity.use_pipeline_uuid
session_type = 'group' if isinstance(message_source, platform_events.GroupMessage) else 'person'
message_list = session.get_message_list(pipeline_uuid)
# 检查是否是新的流式消息通过bot_message对象判断
@@ -197,13 +200,15 @@ class WebSocketAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter)
if is_final and bot_message.tool_calls is None:
message_list[-1] = message_data
# 直接广播到所有该pipeline的连接
# 直接广播到所有该pipeline的连接包含session_type信息
await ws_connection_manager.broadcast_to_pipeline(
pipeline_uuid,
{
'type': 'response',
'session_type': session_type,
'data': message_data.model_dump(),
},
session_type=session_type,
)
return message_data.model_dump()
@@ -344,13 +349,15 @@ class WebSocketAdapter(abstract_platform_adapter.AbstractMessagePlatformAdapter)
)
use_session.get_message_list(pipeline_uuid).append(user_message)
# 广播用户消息到所有连接(包括发送者)
# 广播用户消息到所有连接(包括发送者)包含session_type信息
await ws_connection_manager.broadcast_to_pipeline(
pipeline_uuid,
{
'type': 'user_message',
'session_type': session_type,
'data': user_message.model_dump(),
},
session_type=session_type,
)
# 添加消息源

View File

@@ -134,9 +134,20 @@ class WebSocketConnectionManager:
connection_ids = self.session_connections.get(session_type, set())
return [self.connections[cid] for cid in connection_ids if cid in self.connections]
async def broadcast_to_pipeline(self, pipeline_uuid: str, message: dict):
"""向指定流水线的所有连接广播消息"""
async def broadcast_to_pipeline(self, pipeline_uuid: str, message: dict, session_type: str = None):
"""向指定流水线的所有连接广播消息
Args:
pipeline_uuid: 流水线UUID
message: 要广播的消息
session_type: 可选的会话类型过滤器如果提供则只向匹配的session_type连接广播
"""
connections = await self.get_connections_by_pipeline(pipeline_uuid)
# 如果指定了session_type只向匹配的连接广播
if session_type is not None:
connections = [conn for conn in connections if conn.session_type == session_type]
tasks = []
for conn in connections:
tasks.append(self.send_to_connection(conn.connection_id, message))