"""Feishu signal pipeline mixin.""" from __future__ import annotations from .shared import * class FeishuPipelineGateTaskMixin: async def _handle_create_task_gate( self, *, message: str, sender: str, source_chat_id: str, source_sender_open_id: Optional[str], feishu_message_id: Optional[str], captured_at: Optional[datetime], intent_gate: dict[str, Any], process_started_at: float, ) -> dict[str, Any]: fields = intent_gate.get("fields") if isinstance(intent_gate.get("fields"), dict) else {} operation_payload = { "project_id": _safe_int(fields.get("project_id")), "title": str(fields.get("title") or "").strip(), "description": str(fields.get("description") or "").strip() or None, } clarification_message = str(intent_gate.get("clarification_template") or "").strip() or self._build_task_clarification_message( list(fields.get("missing_fields") or []), ) occurred_at = captured_at or _utc_now() if occurred_at.tzinfo is None: occurred_at = occurred_at.replace(tzinfo=CN_TZ) operator_user = await self._resolve_command_operator_user(sender=sender) if not fields.get("ready"): await self._write_processing_log( feishu_message_id=feishu_message_id, feishu_item_id=None, raw_message=message, ai_raw_output=json.dumps({"intent_gate": intent_gate}, ensure_ascii=False), project_score=1.0 if fields.get("project_id") is not None else None, signal_confidence=0.0 if fields.get("project_id") is not None else None, level="command", routing_decision=ROUTING_INTENT_GATE_CLARIFICATION, routing_reason="建任务缺少必填字段,已转待澄清,禁止猜测执行。", reasoning_bullets=[ "intent gate 命中 create_task。", "当前缺少 task.create 必填字段。", "仅保留结构化待澄清项,不触发执行器。", ], processing_status="success", error_message=None, duration_ms=int((time.perf_counter() - process_started_at) * 1000), normalized_text=message, route=ROUTING_INTENT_GATE_CLARIFICATION, intent=INTENT_CLARIFICATION_REQUIRED, executor="explicit_service", operation_code="task.create", reply_source="deterministic_reply", ) return { "status": "captured", "classification": "command", "project_scope": "command", "linked_project_ids": [int(fields["project_id"])] if fields.get("project_id") is not None else [], "signal_id": None, "created_project_id": None, "auto_tasks": [], "ai_trace_id": f"feishu-task-clarify-{(feishu_message_id or 'noid')[:32]}", "results": [], "intent": INTENT_CLARIFICATION_REQUIRED, "clarification_message": clarification_message, "direct_reply_required": True, "direct_reply_text": clarification_message, } if not self._can_execute_high_value_action(operator_user): queued = await self._queue_command_intent_item( message=message, sender=sender, source_chat_id=source_chat_id, source_sender_open_id=source_sender_open_id, feishu_message_id=feishu_message_id, occurred_at=occurred_at, intent_gate=intent_gate, operation_code="task.create", operation_payload={k: v for k, v in operation_payload.items() if v is not None}, blocking_reason=clarification_message if not fields.get("ready") else "建任务属于高风险动作,当前需要你确认后再执行。", decision_reason="high_value_action_guard", matched_project_id=_safe_int(fields.get("project_id")), ) await self._write_processing_log( feishu_message_id=feishu_message_id, feishu_item_id=_safe_int(queued.get("item_id")), raw_message=message, ai_raw_output=json.dumps({"intent_gate": intent_gate}, ensure_ascii=False), project_score=1.0 if fields.get("project_id") is not None else None, signal_confidence=0.0 if fields.get("project_id") is not None else None, level="command", routing_decision=ROUTING_INTENT_GATE_CLARIFICATION, routing_reason="建任务命中高风险保护,已转待决策/待澄清。", reasoning_bullets=[ "intent gate 命中 create_task。", "当前未满足自动执行条件。", "仅保留结构化待决策项,不做猜测执行。", ], processing_status="success", error_message=None, duration_ms=int((time.perf_counter() - process_started_at) * 1000), normalized_text=message, route=ROUTING_INTENT_GATE_CLARIFICATION, intent=INTENT_CLARIFICATION_REQUIRED if not fields.get("ready") else INTENT_CREATE_TASK, executor="explicit_service", operation_code="task.create", reply_source="deterministic_reply", ) return { "status": "captured", "classification": "command", "project_scope": "command", "linked_project_ids": [int(fields["project_id"])] if fields.get("project_id") is not None else [], "signal_id": None, "created_project_id": None, "auto_tasks": [], "ai_trace_id": f"feishu-task-pending-{queued.get('item_id')}", "results": [queued], "intent": INTENT_CLARIFICATION_REQUIRED if not fields.get("ready") else INTENT_CREATE_TASK, "clarification_message": queued.get("clarification_message"), "direct_reply_required": True, "direct_reply_text": str(queued.get("clarification_message") or "已转待决策。"), } trace_id = f"intent-task-{self._stable_positive_int(message, sender, feishu_message_id)}" execution = await self._execute_controlled_operation( operator_user=operator_user, operation_code="task.create", payload={k: v for k, v in operation_payload.items() if v is not None}, trace_id=trace_id, ) first = execution["results"][0] if execution.get("results") else {} status = str(first.get("status") or "").strip().lower() if status not in {"applied", "skipped"}: raise ValueError(str(first.get("message") or "task.create failed")) project_id = _safe_int(fields.get("project_id")) item_id = await self._record_committed_operation_item( message=message, sender=sender, source_chat_id=source_chat_id, source_sender_open_id=source_sender_open_id, feishu_message_id=feishu_message_id, captured_at=captured_at, intent=INTENT_CREATE_TASK, operation_code="task.create", execution_result=first, matched_project_id=project_id, ) reply_text = self._build_operation_commit_reply({"execution": {"results": [first], "applied_count": 1 if status == "applied" else 0, "skipped_count": 1 if status == "skipped" else 0, "failed_count": 0}}) await self._write_processing_log( feishu_message_id=feishu_message_id, feishu_item_id=item_id, raw_message=message, ai_raw_output=json.dumps({"intent_gate": intent_gate, "execution": execution}, ensure_ascii=False)[:120000], project_score=1.0 if project_id is not None else None, signal_confidence=0.0 if project_id is not None else None, level="command", routing_decision=ROUTING_OPERATION_COMMITTED, routing_reason="建任务已通过 deterministic operation executor 提交,并以真实 DB 结果回执。", reasoning_bullets=[ "intent gate 命中 create_task。", "执行器仅走 task.create。", "回复绑定真实 commit 结果。", ], processing_status="success", error_message=None, duration_ms=int((time.perf_counter() - process_started_at) * 1000), normalized_text=message, route=ROUTING_OPERATION_COMMITTED, intent=INTENT_CREATE_TASK, executor="explicit_service", operation_code="task.create", operation_result=first if isinstance(first, dict) else None, reply_source="db_commit", ) return { "status": "captured", "classification": "command", "project_scope": "command", "linked_project_ids": [int(project_id)] if project_id is not None else [], "signal_id": None, "created_project_id": None, "auto_tasks": [], "ai_trace_id": trace_id, "results": [ { "item_id": item_id, "level": "command", "project_id": int(project_id) if project_id is not None else None, "signal_id": None, "route_status": ROUTE_STATUS_AUTO_DONE, } ], "intent": INTENT_CREATE_TASK, "direct_reply_required": True, "direct_reply_text": reply_text, "command_result": {"execution": execution}, }