From 504b9b2e409ecbdd09f74c213fbd822dac490dae Mon Sep 17 00:00:00 2001 From: hanmolabiqiu Date: Wed, 3 Jun 2026 15:14:56 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20meeting=20room=20support=20=E2=80=94=20?= =?UTF-8?q?forward=20to=20QWEN=20+=20OpenCode,=20[SKIP]=20filtering?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - MEETING_ROOM_INBOX_ID = 22 (开发团队) - handle_meeting_message(): all messages → both AI agents - [SKIP] replies filtered out, rest sent with [QWEN]/[OpenCode] prefix - Routing in _on_message_created for inbox 22 --- chatwoot_ws_agent.py | 74 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/chatwoot_ws_agent.py b/chatwoot_ws_agent.py index 5c89d83..18b9a30 100644 --- a/chatwoot_ws_agent.py +++ b/chatwoot_ws_agent.py @@ -570,6 +570,72 @@ def update_conversation_status(conv_id, status, headers): log(f"Status update error: {e}") return False +# ===== MEETING ROOM ===== +MEETING_ROOM_INBOX_ID = 22 # "开发团队" inbox +MEETING_AGENTS = [ + {"id": "QWEN", "label": "[QWEN]", "agent": "wordpress"}, + {"id": "OpenCode", "label": "[OpenCode]", "agent": "opencode"}, +] +_meeting_ai_sent_ids = set() # track AI-sent message IDs to avoid loop + +def handle_meeting_message(msg_data, headers): + """Handle messages in the 开发团队 meeting room inbox. + + - Messages from AI agents (tracked IDs) → skip (avoid loop) + - Messages from human (qiu) → forward to both QWEN and OpenCode + - AI replies with [SKIP] → don't send to Chatwoot + - Other AI replies → send with [QWEN] or [OpenCode] prefix + """ + msg_id = msg_data.get("id") + if not msg_id or is_processed(msg_id): + return + + content = str(msg_data.get("content", "")).strip() + conv_id = msg_data.get("conversation_id") + if not content or not conv_id: + return + + # Skip AI's own messages (avoid infinite loop) + if msg_id in _meeting_ai_sent_ids: + mark_processed(msg_id) + return + + # Skip private notes + if msg_data.get("private", False): + return + + mark_processed(msg_id) + sender_name = msg_data.get("sender", {}).get("name", "Unknown") + log(f"📩 [会议] msg #{msg_id} from '{sender_name}': {content[:100]}") + + # Forward to each AI agent + for agent_cfg in MEETING_AGENTS: + prompt = ( + f"You are {agent_cfg['id']}, a team member in a dev team meeting room.\n" + f"Message from '{sender_name}':\n\n{content}\n\n" + f"If this message is relevant to you or you have something useful to add, reply normally.\n" + f"If this message is NOT relevant to you, reply with ONLY: [SKIP]\n" + f"Do NOT add any explanation if you reply [SKIP]." + ) + reply = call_qwenpaw_ai(prompt, target_agent=agent_cfg["agent"]) + if not reply: + log(f"⚠️ [会议] {agent_cfg['id']} returned empty", "WARN") + continue + + # Check for [SKIP] + if reply.strip() == "[SKIP]" or "[SKIP]" in reply: + log(f"⏭️ [会议] {agent_cfg['id']} skipped (not relevant)") + continue + + # Send reply with agent label prefix + tagged_reply = f"{agent_cfg['label']} {reply}" + ok, resp = send_reply(conv_id, tagged_reply, headers) + if ok: + _meeting_ai_sent_ids.add(resp.get("id")) + log(f"✅ [会议] {agent_cfg['id']} replied to conv #{conv_id}") + else: + log(f"❌ [会议] {agent_cfg['id']} failed: {resp}", "ERROR") + # ===== MESSAGE HANDLER ===== def handle_incoming_message(msg_data, headers): @@ -781,8 +847,12 @@ class WSAgent: content = str(msg_data.get("content", ""))[:100] log(f"👤 Human agent '{agent_name}' replied in conv #{conv_id}: {content}") - # Process incoming customer messages as before - Thread(target=handle_incoming_message, args=(msg_data, self.headers), daemon=True).start() + # Route to meeting room or normal inbox handler + inbox_id = msg_data.get("inbox_id") + if inbox_id == MEETING_ROOM_INBOX_ID: + Thread(target=handle_meeting_message, args=(msg_data, self.headers), daemon=True).start() + else: + Thread(target=handle_incoming_message, args=(msg_data, self.headers), daemon=True).start() def _on_conversation_updated(self, data): """Handle conversation status changes.