mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-08-08 12:20:58 +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,
|
|
}
|