Merge branch 'master' into feat/mcp-ui

This commit is contained in:
Junyan Qin
2025-10-01 11:07:16 +08:00
20 changed files with 1479 additions and 20 deletions

View File

@@ -96,7 +96,7 @@ class RuntimePipeline:
if query.pipeline_config['output']['misc']['at-sender'] and isinstance(
query.message_event, platform_events.GroupMessage
):
result.user_notice.insert(0, platform_message.At(query.message_event.sender.id))
result.user_notice.insert(0, platform_message.At(target=query.message_event.sender.id))
if await query.adapter.is_stream_output_supported():
await query.adapter.reply_message_chunk(
message_source=query.message_event,

View File

@@ -16,26 +16,17 @@ class AtBotRule(rule_model.GroupRespondRule):
rule_dict: dict,
query: pipeline_query.Query,
) -> entities.RuleJudgeResult:
found = False
def remove_at(message_chain: platform_message.MessageChain):
nonlocal found
for component in message_chain.root:
if isinstance(component, platform_message.At) and component.target == query.adapter.bot_account_id:
message_chain.remove(component)
found = True
break
remove_at(message_chain)
remove_at(message_chain) # 回复消息时会at两次检查并删除重复的
# if message_chain.has(platform_message.At(query.adapter.bot_account_id)) and rule_dict['at']:
# message_chain.remove(platform_message.At(query.adapter.bot_account_id))
# if message_chain.has(
# platform_message.At(query.adapter.bot_account_id)
# ): # 回复消息时会at两次检查并删除重复的
# message_chain.remove(platform_message.At(query.adapter.bot_account_id))
# return entities.RuleJudgeResult(
# matching=True,
# replacement=message_chain,
# )
return entities.RuleJudgeResult(matching=False, replacement=message_chain)
return entities.RuleJudgeResult(matching=found, replacement=message_chain)

View File

@@ -32,6 +32,8 @@ class PluginRuntimeConnector:
handler_task: asyncio.Task
heartbeat_task: asyncio.Task | None = None
stdio_client_controller: stdio_client_controller.StdioClientController
ctrl: stdio_client_controller.StdioClientController | ws_client_controller.WebSocketClientController
@@ -54,6 +56,15 @@ class PluginRuntimeConnector:
self.runtime_disconnect_callback = runtime_disconnect_callback
self.is_enable_plugin = self.ap.instance_config.data.get('plugin', {}).get('enable', True)
async def heartbeat_loop(self):
while True:
await asyncio.sleep(10)
try:
await self.ping_plugin_runtime()
self.ap.logger.debug('Heartbeat to plugin runtime success.')
except Exception as e:
self.ap.logger.debug(f'Failed to heartbeat to plugin runtime: {e}')
async def initialize(self):
if not self.is_enable_plugin:
self.ap.logger.info('Plugin system is disabled.')
@@ -72,6 +83,7 @@ class PluginRuntimeConnector:
return False
self.handler = handler.RuntimeConnectionHandler(connection, disconnect_callback, self.ap)
self.handler_task = asyncio.create_task(self.handler.run())
_ = await self.handler.ping()
self.ap.logger.info('Connected to plugin runtime.')
@@ -85,8 +97,13 @@ class PluginRuntimeConnector:
'runtime_ws_url', 'ws://langbot_plugin_runtime:5400/control/ws'
)
async def make_connection_failed_callback(ctrl: ws_client_controller.WebSocketClientController) -> None:
self.ap.logger.error('Failed to connect to plugin runtime, trying to reconnect...')
async def make_connection_failed_callback(
ctrl: ws_client_controller.WebSocketClientController, exc: Exception = None
) -> None:
if exc is not None:
self.ap.logger.error(f'Failed to connect to plugin runtime({ws_url}): {exc}')
else:
self.ap.logger.error(f'Failed to connect to plugin runtime({ws_url}), trying to reconnect...')
await self.runtime_disconnect_callback(self)
self.ctrl = ws_client_controller.WebSocketClientController(
@@ -106,6 +123,9 @@ class PluginRuntimeConnector:
)
task = self.ctrl.run(new_connection_callback)
if self.heartbeat_task is None:
self.heartbeat_task = asyncio.create_task(self.heartbeat_loop())
asyncio.create_task(task)
async def initialize_plugins(self):
@@ -224,3 +244,7 @@ class PluginRuntimeConnector:
if self.is_enable_plugin and isinstance(self.ctrl, stdio_client_controller.StdioClientController):
self.ap.logger.info('Terminating plugin runtime process...')
self.ctrl.process.terminate()
if self.heartbeat_task is not None:
self.heartbeat_task.cancel()
self.heartbeat_task = None