def _assistant_call(self,method,*args,default=False): """Optional coordination cannot stop the protocol listener or approve work.""" try: if self._review_assistant is None: from review_assistant import ReviewAssistantCoordinator self._review_assistant=ReviewAssistantCoordinator( root=self.path.parent,account=self.account,pid=self.pid,db=self.db,log=self.log) assistant=self._review_assistant if not assistant.enabled():return default return getattr(assistant,method)(*args) except Exception as exc: warning=f'{method}:{type(exc).__name__}' if warning!=self._assistant_warning: self._assistant_warning=warning try:self.log('[医疗助理] 协作状态暂不可用,协议监听继续;'+warning) except Exception:pass return default def _assistant_recipient(self,conv_id): return bool(self._assistant_call('is_recipient',conv_id)) def _assistant_pending(self,state): # Preserve an already-registered review if coordination storage is # temporarily unavailable; never interpret a read failure as approval. if state.get('assistant_review_id') and not state.get('approved'):return True return bool(self._assistant_call('has_pending',state.get('conv_id',''))) def _register_assistant_review(self,key,state,context=None): if _send_protection(state) or state.get('account')!=self.account:return if not state.get('awaiting_review') or state.get('approved'):return if context is None: context=self.db.get_conversation_context_by_id(self.account,state['conv_id'],limit=500) review_id=self._assistant_call('ensure_review',state,context,default='') if review_id and review_id!=state.get('assistant_review_id'): with self._lock: if self._pending.get(key) is state: state['assistant_review_id']=review_id self._save() def _reconcile_assistant_review(self,key,state,context=None): if (state.get('account')!=self.account or _send_protection(state) or not (state.get('awaiting_review') or state.get('assistant_review_id') or self._assistant_call('has_pending',state.get('conv_id','')))): return False if context is None: context=self.db.get_conversation_context_by_id(self.account,state['conv_id'],limit=500) self._register_assistant_review(key,state,context) evidence=self._assistant_call('reconcile',state,context,default=None) if not isinstance(evidence,dict) or not evidence:return False if (evidence.get('review_id') and state.get('assistant_review_id') and evidence['review_id']!=state['assistant_review_id']):return False with self._lock: if self._pending.get(key) is not state or _send_protection(state):return False previous_seen=self._seen.get(key) if state.get('dedup_key'):self._seen[key]=state['dedup_key'] self._pending.pop(key,None) try:self._save() except Exception: self._pending[key]=state if previous_seen is None:self._seen.pop(key,None) else:self._seen[key]=previous_seen raise try: from queue_log import QueueLog QueueLog().append(key,state.get('display_name',''),'已审核', '已检测到当前企微账号人工回复;本轮旧AI草稿已丢弃,后续消息重新执行风控') self.log('[协议已审核] '+state.get('display_name','')+' · 已人工回复,本轮旧AI草稿已丢弃') except Exception:pass self._listening_progress() last=(context or {}).get('last_message') or {} if (last and not last.get('is_self') and last.get('dedup_key')!=state.get('dedup_key') and last.get('account')==self.account and last.get('conv_id')==state.get('conv_id')): self._upsert(last) return True