"""AI PMO reply rendering runtime.""" from __future__ import annotations from typing import Any, Optional from .ai_pmo_intent_routing import ( INTENT_FOLLOWUP_CONFIRM, INTENT_FOLLOWUP_CONTINUE, INTENT_PROJECT_CREATE, INTENT_QUERY, INTENT_SIGNAL_CREATE, INTENT_SIGNAL_SOURCE_ONBOARD, ROUTE_PROJECT_SIGNAL_CANCEL, ROUTE_PROJECT_SIGNAL_COMMIT, ROUTE_PROJECT_SIGNAL_DISCOVER, ROUTE_PROJECT_SIGNAL_REFRESH, CanonicalIntent, ) def _safe_int(value: Any) -> Optional[int]: try: if value is None or value == "": return None return int(value) except (TypeError, ValueError): return None def _normalize_signal_id_list(value: Any) -> list[int]: ids: list[int] = [] seen: set[int] = set() if isinstance(value, list): items = value else: items = [value] for item in items: signal_id = _safe_int(item) if signal_id is None or signal_id <= 0: continue if signal_id in seen: continue seen.add(signal_id) ids.append(signal_id) return ids class ReplyRenderer: """唯一回执出口。""" def __init__( self, *, state_waiting_manual: str, state_failed: str, receipt_phase_action: str, receipt_phase_pending: str, receipt_phase_error: str, ) -> None: self.state_waiting_manual = state_waiting_manual self.state_failed = state_failed self.receipt_phase_action = receipt_phase_action self.receipt_phase_pending = receipt_phase_pending self.receipt_phase_error = receipt_phase_error def render( self, *, work_state: str, intent: CanonicalIntent, decision_record: dict[str, Any], execution_result: dict[str, Any], ) -> dict[str, Any]: if work_state == self.state_waiting_manual: if intent.name in {INTENT_FOLLOWUP_CONFIRM, INTENT_FOLLOWUP_CONTINUE}: followup_text = str(execution_result.get("followup_reply") or "").strip() if followup_text: return { "receipt_phase": self.receipt_phase_pending, "template_key": "pending_manual", "payload": {"intent": intent.name, "reason": followup_text}, "text": followup_text, } if intent.name == INTENT_SIGNAL_CREATE: pending_text = str(execution_result.get("followup_reply") or "").strip() if pending_text: return { "receipt_phase": self.receipt_phase_pending, "template_key": "pending_manual", "payload": { "intent": intent.name, "workflow_route": execution_result.get("workflow_route"), "reason": pending_text, }, "text": pending_text, } gate_message = str(((decision_record.get("approval_requirement") or {}).get("message")) or "").strip() if not gate_message: gate_message = "已进入待人工确认队列。" return { "receipt_phase": self.receipt_phase_pending, "template_key": "pending_manual", "payload": {"intent": intent.name, "reason": gate_message}, "text": gate_message, } if work_state == self.state_failed: if intent.name in {INTENT_FOLLOWUP_CONFIRM, INTENT_FOLLOWUP_CONTINUE}: followup_text = str(execution_result.get("followup_reply") or "").strip() if followup_text: return { "receipt_phase": self.receipt_phase_error, "template_key": "safe_error", "payload": {"intent": intent.name, "reason": followup_text}, "text": followup_text, } reason = str(execution_result.get("error_message") or "系统处理中出现异常,本次未执行。").strip() return { "receipt_phase": self.receipt_phase_error, "template_key": "safe_error", "payload": {"intent": intent.name, "reason": reason}, "text": reason, } if intent.name in {INTENT_FOLLOWUP_CONFIRM, INTENT_FOLLOWUP_CONTINUE}: followup_text = str(execution_result.get("followup_reply") or "已继续处理。").strip() return { "receipt_phase": self.receipt_phase_action, "template_key": "action_succeeded", "payload": { "intent": intent.name, "target_work_item_id": _safe_int(execution_result.get("target_work_item_id")), "target_state": execution_result.get("target_state"), }, "text": followup_text, } if intent.name == INTENT_QUERY: answer = str(execution_result.get("answer") or "当前暂无可用回答。").strip() return { "receipt_phase": self.receipt_phase_action, "template_key": "action_succeeded", "payload": {"intent": intent.name, "answer": answer}, "text": answer, } if intent.name == INTENT_PROJECT_CREATE: project = execution_result.get("project") if isinstance(execution_result.get("project"), dict) else {} project_id = _safe_int(project.get("id")) project_title = str(project.get("title") or project.get("name") or "新项目").strip() return { "receipt_phase": self.receipt_phase_action, "template_key": "action_succeeded", "payload": {"intent": intent.name, "project_id": project_id, "project_title": project_title}, "text": f"已立项:项目#{project_id}《{project_title}》已创建完成。" if project_id else f"已立项:《{project_title}》已创建完成。", } if intent.name == INTENT_SIGNAL_SOURCE_ONBOARD: signal_id = _safe_int(execution_result.get("signal_id")) workflow = execution_result.get("signal_source_workflow") if isinstance(execution_result.get("signal_source_workflow"), dict) else {} status = str(workflow.get("status") or (execution_result.get("signal_source_orchestration") or {}).get("status") or "").strip() if status == "pending_manual": return { "receipt_phase": self.receipt_phase_pending, "template_key": "pending_manual", "payload": {"intent": intent.name, "signal_id": signal_id, "status": status}, "text": f"已记录信号源接入请求,当前为待人工确认。信号#{signal_id} 已入库。" if signal_id else "已记录信号源接入请求,当前为待人工确认。", } return { "receipt_phase": self.receipt_phase_action, "template_key": "action_succeeded", "payload": {"intent": intent.name, "signal_id": signal_id, "status": status}, "text": f"已接收入库并启动信号源接入流程。信号#{signal_id},状态:{status or 'running'}。", } workflow_route = str(execution_result.get("workflow_route") or "").strip().lower() followup_text = str(execution_result.get("followup_reply") or "").strip() if followup_text and workflow_route in { ROUTE_PROJECT_SIGNAL_DISCOVER, ROUTE_PROJECT_SIGNAL_COMMIT, ROUTE_PROJECT_SIGNAL_CANCEL, ROUTE_PROJECT_SIGNAL_REFRESH, }: return { "receipt_phase": self.receipt_phase_action, "template_key": "action_succeeded", "payload": { "intent": intent.name, "workflow_route": workflow_route, }, "text": followup_text, } signal_ids = _normalize_signal_id_list(execution_result.get("signal_ids")) signal_id = _safe_int(execution_result.get("signal_id")) if signal_id is not None and signal_id not in signal_ids: signal_ids = [signal_id, *signal_ids] primary_signal_id = signal_ids[0] if signal_ids else signal_id project_id = _safe_int(execution_result.get("project_id")) if len(signal_ids) > 1 and project_id is not None: signal_labels = "、".join(f"#{sid}" for sid in signal_ids[:5]) text = f"已入库:已为项目#{project_id}创建{len(signal_ids)}条信号({signal_labels})。" elif len(signal_ids) > 1: signal_labels = "、".join(f"#{sid}" for sid in signal_ids[:5]) text = f"已入库:已创建{len(signal_ids)}条信号({signal_labels})。" elif primary_signal_id is not None and project_id is not None: text = f"已入库:已为项目#{project_id}创建信号#{primary_signal_id}。" elif primary_signal_id is not None: text = f"已入库:已创建信号#{primary_signal_id}。" else: text = "已收到并入库。" return { "receipt_phase": self.receipt_phase_action, "template_key": "action_succeeded", "payload": { "intent": intent.name, "signal_id": primary_signal_id, "signal_ids": signal_ids, "project_id": project_id, }, "text": text, }