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 ''}")