From 901a9255e635029726a971e41ff25537bce6090e Mon Sep 17 00:00:00 2001 From: Junyan Qin Date: Sun, 24 May 2026 14:38:57 +0800 Subject: [PATCH] fix(pipelines): stop attributing dashboard debug WS to bound web_page_bot The dashboard pipeline-debug WebSocket (/api/v1/pipelines//ws/connect) and the embed widget WebSocket (/api/v1/embed//ws/connect) already live on separate paths, but the debug handler ran `_find_owner_bot(pipeline_uuid)` and, when the same pipeline happened to be bound to a web_page_bot, passed that bot as `owner_bot` into `handle_websocket_message`. The adapter then used the page bot's listeners + adapter for the request, so debug sessions were logged as "page bot" activity in the dashboard. Debug sessions must always run under the built-in websocket_proxy_bot. Remove `_find_owner_bot`, drop the `owner_bot` parameter from the debug-path `_handle_receive`, and call `handle_websocket_message` without it so the adapter takes its default proxy-bot branch. The embed handler still resolves and passes its `runtime_bot` for the page-bot path, so attribution there is unchanged. --- .../groups/pipelines/websocket_chat.py | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/langbot/pkg/api/http/controller/groups/pipelines/websocket_chat.py b/src/langbot/pkg/api/http/controller/groups/pipelines/websocket_chat.py index c85ecc77..ebe46b8f 100644 --- a/src/langbot/pkg/api/http/controller/groups/pipelines/websocket_chat.py +++ b/src/langbot/pkg/api/http/controller/groups/pipelines/websocket_chat.py @@ -43,8 +43,12 @@ class WebSocketChatRouterGroup(group.RouterGroup): await quart.websocket.send(json.dumps({'type': 'error', 'message': 'WebSocket adapter not found'})) return - # Find the owning bot for this pipeline (e.g. a web_page_bot) - owner_bot = self._find_owner_bot(pipeline_uuid) + # Dashboard pipeline-debug sessions must always run under the + # built-in websocket_proxy_bot identity. We deliberately do NOT + # resolve a web_page_bot owner here — even if one is bound to + # the same pipeline, debug requests must not be attributed to + # it. The embed widget path (`/api/v1/embed//ws/connect`) + # is the one that carries the page-bot identity. # 注册连接 connection = await ws_connection_manager.add_connection( @@ -73,7 +77,7 @@ class WebSocketChatRouterGroup(group.RouterGroup): ) # 创建接收和发送任务 - receive_task = asyncio.create_task(self._handle_receive(connection, websocket_adapter, owner_bot)) + receive_task = asyncio.create_task(self._handle_receive(connection, websocket_adapter)) send_task = asyncio.create_task(self._handle_send(connection)) # 等待任务完成 @@ -181,14 +185,7 @@ class WebSocketChatRouterGroup(group.RouterGroup): except Exception as e: return self.http_status(500, -1, f'Internal server error: {str(e)}') - def _find_owner_bot(self, pipeline_uuid: str): - """Find a user-created bot (e.g. web_page_bot) that owns this pipeline.""" - for bot in self.ap.platform_mgr.bots: - if bot.bot_entity.adapter == 'web_page_bot' and bot.bot_entity.use_pipeline_uuid == pipeline_uuid: - return bot - return None - - async def _handle_receive(self, connection, websocket_adapter, owner_bot=None): + async def _handle_receive(self, connection, websocket_adapter): """处理接收消息的任务""" try: while connection.is_active: @@ -213,7 +210,10 @@ class WebSocketChatRouterGroup(group.RouterGroup): logger.debug(f'收到消息: {data} from {connection.connection_id}') # 处理消息(不等待响应,响应会通过broadcast异步发送) - await websocket_adapter.handle_websocket_message(connection, data, owner_bot=owner_bot) + # owner_bot is intentionally NOT passed: the dashboard + # debug WebSocket must always run under the proxy bot, + # never under a coincidentally-bound web_page_bot. + await websocket_adapter.handle_websocket_message(connection, data) elif message_type == 'disconnect': # 客户端主动断开