160 lines
6.1 KiB
Python
160 lines
6.1 KiB
Python
from __future__ import annotations
|
|
|
|
from .shared import *
|
|
|
|
class FeishuReceiveRoutingMixin:
|
|
async def _route_scene_reply(
|
|
self,
|
|
*,
|
|
scene: str,
|
|
result: Dict[str, Any],
|
|
message_content: str,
|
|
chat_id: str,
|
|
sender_open_id: Optional[str],
|
|
sender_name: str,
|
|
mentioned_bot_names: List[str],
|
|
trace_id: str,
|
|
message_id: str,
|
|
perf_t0: Optional[float],
|
|
) -> str:
|
|
reply_route = "none"
|
|
capability_reply = self._build_capability_reply(message_content)
|
|
if scene == "execute":
|
|
if self._is_duplicate_capture_result(result):
|
|
self._emit_state_transition(
|
|
trace_id=trace_id,
|
|
state="ROUTED",
|
|
route="duplicate_suppressed",
|
|
)
|
|
return reply_route
|
|
|
|
self._emit_state_transition(
|
|
trace_id=trace_id,
|
|
state="ROUTED",
|
|
route="tool_first_execute",
|
|
)
|
|
deterministic_reply = capability_reply or str(result.get("direct_reply_text") or "").strip()
|
|
if not deterministic_reply:
|
|
deterministic_reply = self._build_execution_receipt_reply(
|
|
message_content=message_content,
|
|
capture_result=result,
|
|
)
|
|
deterministic_reply, guard_reason = self._guard_execute_reply_text_with_reason(
|
|
deterministic_reply,
|
|
trace_id=trace_id,
|
|
)
|
|
if guard_reason:
|
|
asyncio.create_task(
|
|
self._record_execute_guard_alert(
|
|
trace_id=trace_id,
|
|
message_id=message_id,
|
|
message_content=message_content,
|
|
capture_result=result,
|
|
guard_reason=guard_reason,
|
|
)
|
|
)
|
|
if not deterministic_reply and str(result.get("status") or "").lower() == "error":
|
|
deterministic_reply = self._build_error_reply_text()
|
|
if chat_id and deterministic_reply:
|
|
await self._safe_reply_text(
|
|
chat_id=chat_id,
|
|
mention_open_id=sender_open_id,
|
|
mention_name=sender_name,
|
|
text=deterministic_reply,
|
|
trace_id=trace_id,
|
|
source_message_id=message_id,
|
|
perf_t0=perf_t0,
|
|
)
|
|
return "execute_template"
|
|
return reply_route
|
|
|
|
if scene == "qa":
|
|
self._emit_state_transition(
|
|
trace_id=trace_id,
|
|
state="ROUTED",
|
|
route="qa_consult",
|
|
)
|
|
if chat_id and capability_reply:
|
|
await self._safe_reply_text(
|
|
chat_id=chat_id,
|
|
mention_open_id=sender_open_id,
|
|
mention_name=sender_name,
|
|
text=capability_reply,
|
|
trace_id=trace_id,
|
|
source_message_id=message_id,
|
|
perf_t0=perf_t0,
|
|
)
|
|
return "qa_capability"
|
|
if chat_id and bool(result.get("direct_reply_required")):
|
|
await self._safe_reply_text(
|
|
chat_id=chat_id,
|
|
mention_open_id=sender_open_id,
|
|
mention_name=sender_name,
|
|
text=str(result.get("direct_reply_text") or "已收到,正在处理。"),
|
|
trace_id=trace_id,
|
|
source_message_id=message_id,
|
|
perf_t0=perf_t0,
|
|
)
|
|
return "qa_direct"
|
|
if chat_id and self._should_reply_to_mention(
|
|
mentioned_bot_names=mentioned_bot_names,
|
|
message_content=message_content,
|
|
):
|
|
await self._reply_with_active_role_prompt(
|
|
chat_id=chat_id,
|
|
sender_open_id=sender_open_id,
|
|
sender_name=sender_name,
|
|
message_content=message_content,
|
|
capture_result=result,
|
|
trace_id=trace_id,
|
|
source_message_id=message_id,
|
|
perf_t0=perf_t0,
|
|
)
|
|
return "qa_llm"
|
|
return reply_route
|
|
|
|
self._emit_state_transition(
|
|
trace_id=trace_id,
|
|
state="ERROR_REPLY",
|
|
reason="scene_error",
|
|
capture_status=str(result.get("status") or "unknown"),
|
|
)
|
|
if chat_id:
|
|
await self._safe_reply_text(
|
|
chat_id=chat_id,
|
|
mention_open_id=sender_open_id,
|
|
mention_name=sender_name,
|
|
text=self._build_error_reply_text(),
|
|
trace_id=trace_id,
|
|
source_message_id=message_id,
|
|
perf_t0=perf_t0,
|
|
)
|
|
return "error_template"
|
|
return reply_route
|
|
|
|
@staticmethod
|
|
def _classify_message_scene(*, capture_result: Dict[str, Any]) -> str:
|
|
if not isinstance(capture_result, dict):
|
|
return "error"
|
|
status = str(capture_result.get("status") or "").strip().lower()
|
|
classification = str(capture_result.get("classification") or "").strip().lower()
|
|
if status in {"captured", "ignored"}:
|
|
return "execute"
|
|
if status == "answered" or classification in {"question", "qa"}:
|
|
return "qa"
|
|
if status == "error" or classification == "error":
|
|
return "error"
|
|
return "qa"
|
|
|
|
@staticmethod
|
|
def _build_error_reply_text() -> str:
|
|
return "系统处理中出现异常,本次未执行。请稍后重试,或补充更明确的目标、对象和动作。"
|
|
|
|
@staticmethod
|
|
def _emit_state_transition(trace_id: str, state: str, **payload: Any) -> None:
|
|
safe_trace = str(trace_id or "unknown")
|
|
safe_state = str(state or "unknown")
|
|
details = ", ".join([f"{k}={v}" for k, v in payload.items()]) if payload else ""
|
|
print(f"[Feishu-SM][{safe_trace}] state={safe_state}{', ' + details if details else ''}")
|
|
|