from pathlib import Path import shutil root = Path('C:/wechat_rpa') target = root / 'protocol_engine.py' text = target.read_text(encoding='utf-8') def replace(old, new): global text assert text.count(old) == 1, (old[:100], text.count(old)) text = text.replace(old, new) replace("def _unanswered_manual_reason(context):", """MANUAL_MEDIA_REASON = '当前未回复消息包含图片、语音或其他非文本内容,协议版需人工处理' MANUAL_BATCH_REASON = '连续未回复消息超过 100 条,无法保证问题完整,请人工处理后继续' MANUAL_NON_TEXT_REASON = '当前协议版只自动处理文本消息' def _restore_review_details(state): # Existing persisted queues predate the desktop's explicit review fields. # Recover presentation metadata without granting approval or replaying sends. if state.get('awaiting_review') and not state.get('approved'): state['review_reason'] = str(state.get('review_reason') or state.get('stage_detail') or '人工审核后点击“通过并发送”') if state.get('stage') == 'error' and state.get('last_error') in ( MANUAL_MEDIA_REASON, MANUAL_BATCH_REASON, MANUAL_NON_TEXT_REASON): state.update(manual_required=True, manual_reason=state['last_error']) def _unanswered_manual_reason(context):""") replace("if not _is_text_message(message):return '当前未回复消息包含图片、语音或其他非文本内容,协议版需人工处理'", "if not _is_text_message(message):return MANUAL_MEDIA_REASON") replace("if count>100:return '连续未回复消息超过 100 条,无法保证问题完整,请人工处理后继续'", "if count>100:return MANUAL_BATCH_REASON") replace(" for key,state in list(self._pending.items()):\n lookup", " for key,state in list(self._pending.items()):\n _restore_review_details(state)\n lookup") replace(" if not _is_text_message(state):manual_reason=manual_reason or '当前协议版只自动处理文本消息'\n if manual_reason:\n with self._lock:state.update(reply_text='',staged_reply_text='',approved=False,awaiting_review=False)\n self._stage(key,'error','当前消息需要人工处理',manual_reason);return", """ if not _is_text_message(state):manual_reason=manual_reason or MANUAL_NON_TEXT_REASON if manual_reason: lines=[] for message in reversed((context or {}).get('messages') or []): if message.get('is_self') or system_contact_status(message)=='restored':break lines.append(str(message.get('content') or '(非文本消息)')) if len(lines)>=101:break with self._lock: state.update(reply_text='',staged_reply_text='',approved=False,awaiting_review=False, review_reason='',manual_required=True,manual_reason=manual_reason, chat_text=str((context or {}).get('text') or ''),last_lines=list(reversed(lines))) self._stage(key,'error','当前消息需要人工处理',manual_reason);return""") replace(" with self._lock:state['awaiting_review']=True\n self._stage(key,'awaiting_review',reason)", " with self._lock:state.update(awaiting_review=True,review_reason=reason,manual_required=False,manual_reason='')\n self._stage(key,'awaiting_review',reason)") replace(" if s is None:result['missing'].append(key);continue\n if s.get('send_state')", " if s is None:result['missing'].append(key);continue\n if s.get('account')!=self.account:result['protected'].append(key);continue\n if s.get('send_state')") replace(" if s.get('awaiting_review') and s.get('reply_text'):s.update(approved=True,awaiting_review=False);result['approved'].append(key)", """ if s.get('awaiting_review') and s.get('reply_text') and not s.get('manual_required'): now=time.time() s.update(approved=True,awaiting_review=False,review_reason='',stage='ready_to_send', stage_detail='审核已通过,等待发送前核对',stage_started_at=now,updated_at=now) result['approved'].append(key)""") replace(" if s.get('stage')=='error':s.update(stage='queued',last_error='',ready_at=time.time(),reply_text='',approved=False);result['retried'].append(key)", """ if s.get('stage')=='error': now=time.time() s.update(stage='queued',stage_detail='等待重新处理',stage_started_at=now,updated_at=now, last_error='',ready_at=now,reply_text='',staged_reply_text='',approved=False, awaiting_review=False,review_reason='',manual_required=False,manual_reason='') result['retried'].append(key)""") compile(text, str(target), 'exec') backup = root / 'backups/review-visibility-20260916' backup.mkdir(parents=True, exist_ok=True) assert not (backup / target.name).exists(), 'Backup already exists; do not rerun' shutil.copy2(target, backup / target.name) target.write_text(text, encoding='utf-8') shutil.copy2(Path(__file__).with_name('test_protocol_review_visibility.py'), root / 'test_protocol_review_visibility.py') print('Updated protocol review metadata and isolated tests; backup:', backup)