mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-02 12:05:54 +00:00
142 lines
5.6 KiB
Python
142 lines
5.6 KiB
Python
"""Reply Message Node - reply to the triggering message
|
||
|
||
Node metadata is loaded from: ../../templates/metadata/nodes/reply_message.yaml
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import logging
|
||
from typing import Any
|
||
|
||
from langbot_plugin.api.entities.builtin.workflow.entities import ExecutionContext
|
||
from ..node import WorkflowNode, workflow_node
|
||
from .. import monitoring_helper
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
@workflow_node('reply_message')
|
||
class ReplyMessageNode(WorkflowNode):
|
||
"""Reply message node - reply to the triggering message"""
|
||
|
||
category = 'action'
|
||
|
||
async def execute(self, inputs: dict[str, Any], context: ExecutionContext) -> dict[str, Any]:
|
||
# Priority: content/response (from upstream nodes) > message (original input) > context
|
||
message = inputs.get('content')
|
||
if message in (None, ''):
|
||
message = inputs.get('response')
|
||
if message in (None, ''):
|
||
message = inputs.get('input')
|
||
if message in (None, ''):
|
||
message = inputs.get('message')
|
||
if message in (None, '') and context.message_context:
|
||
message = context.message_context.message_content
|
||
if message is None:
|
||
message = ''
|
||
|
||
template = self.get_config('message_template')
|
||
|
||
if template:
|
||
message = template
|
||
for key, value in inputs.items():
|
||
try:
|
||
message = message.replace(f'{{{{{key}}}}}', str(value) if value is not None else '')
|
||
except Exception as e:
|
||
logger.debug(
|
||
'ReplyMessageNode failed to replace input template variable',
|
||
extra={'node_id': self.node_id, 'key': str(key), 'error': str(e)},
|
||
)
|
||
for key, value in context.variables.items():
|
||
try:
|
||
message = message.replace(f'{{{{variables.{key}}}}}', str(value) if value is not None else '')
|
||
except Exception as e:
|
||
logger.debug(
|
||
'ReplyMessageNode failed to replace context template variable',
|
||
extra={'node_id': self.node_id, 'key': str(key), 'error': str(e)},
|
||
)
|
||
|
||
message_str = str(message) if message is not None else ''
|
||
|
||
logger.info(
|
||
'ReplyMessageNode resolved message',
|
||
extra={
|
||
'node_id': self.node_id,
|
||
'execution_id': context.execution_id,
|
||
'input_keys': list(inputs.keys()),
|
||
'message_preview': message_str[:200],
|
||
'has_template': bool(template),
|
||
'session_id': context.session_id,
|
||
},
|
||
)
|
||
|
||
if not message_str.strip():
|
||
logger.warning(
|
||
'ReplyMessageNode has empty message after resolution',
|
||
extra={
|
||
'node_id': self.node_id,
|
||
'execution_id': context.execution_id,
|
||
'input_keys': list(inputs.keys()),
|
||
},
|
||
)
|
||
|
||
# 实际发送消息
|
||
send_success = False
|
||
send_error = None
|
||
if self.ap:
|
||
try:
|
||
from langbot_plugin.api.entities.builtin.platform.message import MessageChain, Plain
|
||
|
||
message_chain = MessageChain([Plain(text=message_str)])
|
||
# 从 trigger_data 中获取 session_type,而不是从未设置的 context.target_type
|
||
target_type = 'person'
|
||
if context.trigger_data:
|
||
target_type = context.trigger_data.get('session_type', 'person') or 'person'
|
||
session_id = context.session_id or 'unknown'
|
||
target_id = f'websocket_{session_id}'
|
||
|
||
await self.ap.platform_mgr.websocket_proxy_bot.adapter.send_message(
|
||
target_type=target_type,
|
||
target_id=target_id,
|
||
message=message_chain,
|
||
)
|
||
send_success = True
|
||
except Exception as e:
|
||
send_error = str(e)
|
||
logger.error('ReplyMessageNode send message failed: %s', e, exc_info=True)
|
||
else:
|
||
send_error = 'Missing application instance'
|
||
logger.warning(
|
||
'ReplyMessageNode missing application instance',
|
||
extra={
|
||
'node_id': self.node_id,
|
||
'execution_id': context.execution_id,
|
||
},
|
||
)
|
||
|
||
# Record reply log
|
||
try:
|
||
if self.ap and context.query and send_success:
|
||
workflow_id = context.workflow_id or ''
|
||
workflow_name = context.variables.get('_workflow_name', 'Workflow')
|
||
bot_name = context.variables.get('_bot_name', 'Workflow')
|
||
node_name = self.get_config('name', self.node_id)
|
||
await monitoring_helper.WorkflowMonitoringHelper.record_reply_log(
|
||
ap=self.ap,
|
||
query=context.query,
|
||
workflow_id=workflow_id,
|
||
workflow_name=workflow_name,
|
||
node_name=node_name,
|
||
reply_content=message_str,
|
||
bot_name=bot_name,
|
||
context_vars=context.variables,
|
||
)
|
||
except Exception as e:
|
||
logger.warning(f'[ReplyMessage:{self.node_id}] Failed to record reply log: {e}')
|
||
|
||
return {
|
||
'status': 'sent' if send_success else 'failed',
|
||
'message_content': message_str,
|
||
'message_preview': message_str[:200],
|
||
'error': send_error,
|
||
}
|