feat: meeting room support — forward to QWEN + OpenCode, [SKIP] filtering

- 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
This commit is contained in:
hanmolabiqiu
2026-06-03 15:14:56 +08:00
parent ad8243d9d7
commit 504b9b2e40
+72 -2
View File
@@ -570,6 +570,72 @@ def update_conversation_status(conv_id, status, headers):
log(f"Status update error: {e}") log(f"Status update error: {e}")
return False 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 ===== # ===== MESSAGE HANDLER =====
def handle_incoming_message(msg_data, headers): def handle_incoming_message(msg_data, headers):
@@ -781,8 +847,12 @@ class WSAgent:
content = str(msg_data.get("content", ""))[:100] content = str(msg_data.get("content", ""))[:100]
log(f"👤 Human agent '{agent_name}' replied in conv #{conv_id}: {content}") log(f"👤 Human agent '{agent_name}' replied in conv #{conv_id}: {content}")
# Process incoming customer messages as before # Route to meeting room or normal inbox handler
Thread(target=handle_incoming_message, args=(msg_data, self.headers), daemon=True).start() 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): def _on_conversation_updated(self, data):
"""Handle conversation status changes. """Handle conversation status changes.