Files
LangBot/src/langbot/pkg/pipeline/process/handlers/command.py
T
Hyu 3ca724d18e fix: use per-bot admins for command events (#2359)
* fix: use per-bot admins for command events

* style: format rerank provider changes

---------

Co-authored-by: dadachann <185672915+dadachann@users.noreply.github.com>
2026-07-26 17:02:51 +08:00

128 lines
5.0 KiB
Python

from __future__ import annotations
import typing
import sqlalchemy
from .. import handler
from ... import entities
from ... import plugin_diagnostics
from ....entity.persistence.bot import BotAdmin
import langbot_plugin.api.entities.builtin.provider.message as provider_message
import langbot_plugin.api.entities.builtin.provider.session as provider_session
import langbot_plugin.api.entities.builtin.pipeline.query as pipeline_query
import langbot_plugin.api.entities.events as events
class CommandHandler(handler.MessageHandler):
async def handle(
self,
query: pipeline_query.Query,
) -> typing.AsyncGenerator[entities.StageProcessResult, None]:
"""Process"""
full_command_text = str(query.message_chain).strip()
command_text = full_command_text[1:]
privilege = 1
admins = await self.ap.persistence_mgr.execute_async(
sqlalchemy.select(BotAdmin).where(
BotAdmin.bot_uuid == (query.bot_uuid or ''),
BotAdmin.launcher_type == query.launcher_type.value,
BotAdmin.launcher_id == str(query.launcher_id),
)
)
if admins.first() is not None:
privilege = 2
spt = command_text.split(' ')
event_class = (
events.PersonCommandSent
if query.launcher_type == provider_session.LauncherTypes.PERSON
else events.GroupCommandSent
)
event = event_class(
launcher_type=query.launcher_type.value,
launcher_id=query.launcher_id,
sender_id=query.sender_id,
command=spt[0],
params=spt[1:] if len(spt) > 1 else [],
text_message=full_command_text,
is_admin=(privilege == 2),
query=query,
)
# Get bound plugins for filtering
bound_plugins = query.variables.get('_pipeline_bound_plugins', None)
event_ctx = await self.ap.plugin_connector.emit_event(event, bound_plugins)
if event_ctx.is_prevented_default():
if event_ctx.event.reply_message_chain is not None:
mc = event_ctx.event.reply_message_chain
plugin_diagnostics.record_pending_plugin_response_source(
query,
mc,
plugin_diagnostics.get_response_sources(event_ctx),
plugin_diagnostics.get_emitted_plugins(event_ctx),
event.event_name,
)
query.resp_messages.append(mc)
yield entities.StageProcessResult(result_type=entities.ResultType.CONTINUE, new_query=query)
else:
yield entities.StageProcessResult(result_type=entities.ResultType.INTERRUPT, new_query=query)
else:
session = await self.ap.sess_mgr.get_session(query)
async for ret in self.ap.cmd_mgr.execute(
command_text=command_text, full_command_text=full_command_text, query=query, session=session
):
if ret.error is not None:
query.resp_messages.append(
provider_message.Message(
role='command',
content=str(ret.error),
)
)
self.ap.logger.info(f'Command({query.query_id}) error: {self.cut_str(str(ret.error))}')
yield entities.StageProcessResult(result_type=entities.ResultType.CONTINUE, new_query=query)
elif (
ret.text is not None
or ret.image_url is not None
or ret.image_base64 is not None
or ret.file_url is not None
):
content: list[provider_message.ContentElement] = []
if ret.text is not None:
content.append(provider_message.ContentElement.from_text(ret.text))
if ret.image_url is not None:
content.append(provider_message.ContentElement.from_image_url(ret.image_url))
if ret.image_base64 is not None:
content.append(provider_message.ContentElement.from_image_base64(ret.image_base64))
if ret.file_url is not None:
# 此时为 file 类型
content.append(provider_message.ContentElement.from_file_url(ret.file_url, ret.file_name))
query.resp_messages.append(
provider_message.Message(
role='command',
content=content,
)
)
self.ap.logger.info(f'Command returned: {self.cut_str(str(content[0]))}')
yield entities.StageProcessResult(result_type=entities.ResultType.CONTINUE, new_query=query)
else:
yield entities.StageProcessResult(result_type=entities.ResultType.INTERRUPT, new_query=query)