diff --git a/xmpp_agent_core.py b/xmpp_agent_core.py index 9745b4b..a88181b 100644 --- a/xmpp_agent_core.py +++ b/xmpp_agent_core.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """XMPP Bot - 统一版,支持 --agent mohe|zhiwei|xiao 参数""" -import asyncio, logging, ssl, json, urllib.request, os, time, sys, re, sqlite3 +import asyncio, logging, ssl, json, urllib.request, os, time, sys, re from slixmpp import ClientXMPP # ── Agent 配置 ────────────────────────────────────────────── @@ -104,6 +104,8 @@ class AgentBot(ClientXMPP): self._call_seq = 0 self._muc_joined = False self._recent_sent = [] + self._coordinator = 'mohe' # 默认协调者 + self._granted = None async def on_connected(self, event): logging.info(f"🔗 {AGENT_NAME} TCP连接已建立") @@ -139,50 +141,31 @@ class AgentBot(ClientXMPP): if nickname == AGENT_NICK: return - # Coordinator 模式:读取当前协调者和被授权发言者 - _coordinator = None - _granted = None - try: - _cdb = sqlite3.connect('/home/hmo/.hermes/state.db') - _crow = _cdb.execute("SELECT value FROM state_meta WHERE key='coregroup_coordinator'").fetchone() - _grow = _cdb.execute("SELECT value FROM state_meta WHERE key='coregroup_granted_speaker'").fetchone() - _cdb.close() - if _crow: _coordinator = _crow[0] - if _grow: _granted = _grow[0] - except Exception: - pass + # Coordinator 模式 — 全走 XMPP 消息,不依赖共享 DB - # hmo 可以动态切换 coordinator + # 1. hmo 切换 coordinator → 所有 bot 检测,各自更新本地状态 if nickname == 'hmo' and 'coordinator=' in body.lower(): for _name in ['mohe', 'zhiwei', 'xxm']: if f'coordinator={_name}' in body.lower(): - try: - _wdb = sqlite3.connect('/home/hmo/.hermes/state.db') - _wdb.execute("INSERT OR REPLACE INTO state_meta (key, value) VALUES ('coregroup_coordinator', ?)", (_name,)) - _wdb.execute("DELETE FROM state_meta WHERE key='coregroup_granted_speaker'") - _wdb.commit() - _wdb.close() - _coordinator = _name - _granted = None - logging.info(f"👑 Coordinator 切换为 {_name}") - except Exception: - pass + self._coordinator = _name + self._granted = None + logging.info(f"👑 Coordinator 切换为 {_name}") break - # 判断当前 bot 能否处理这条消息 - _can_speak = False - if _coordinator == AGENT_NICK: - _can_speak = True # 协调者始终能说 - if _granted == AGENT_NICK: - _can_speak = True # 被授权者也能说 - # 用完后自动清除授权(一次性) - try: - _wdb = sqlite3.connect('/home/hmo/.hermes/state.db') - _wdb.execute("DELETE FROM state_meta WHERE key='coregroup_granted_speaker'") - _wdb.commit() - _wdb.close() - except Exception: - pass + # 2. 检测其他 bot 发出的授权信号 [GRANT:xxx] + _grant_match = re.search(r'\[GRANT:(\w+)\]', body) + if _grant_match: + self._granted = _grant_match.group(1) + logging.info(f"🎤 收到授权:{self._granted} 获得发言权") + + # 3. 判断当前 bot 能否处理这条消息 + _coordinator = getattr(self, '_coordinator', AGENT_NICK) + _granted = getattr(self, '_granted', None) + _can_speak = (_coordinator == AGENT_NICK) or (_granted == AGENT_NICK) + + if _can_speak and _granted == AGENT_NICK: + # 被授权者用完即收回 + self._granted = None if not _can_speak: return # 代码层拦截,不走 LLM @@ -208,9 +191,9 @@ class AgentBot(ClientXMPP): "3. 别人说错了关键事实,不纠正会有后果\n" "如果以上都不符合,你的回复必须只包含 __SILENT__ 这10个字符," "不要有任何其他内容(不要前缀、不要解释、不要标点、不要空格)。\n\n" - "注意:你是当前群聊的协调者(coordinator)。如果你认为这个问题应该由其他 Agent 回答," - "可以在回复中包含 [GRANT:agent名] 标记(例如 [GRANT:zhiwei]),bot 会自动授权该 Agent 发言一次。" - "授权后该 Agent 的回复会出现在群里,你不需要自己回答。\n\n" + "注意:你是协调者(coordinator)。如果你认为某个问题应该由其他 Agent 回答," + "可以在回复中加入 [GRANT:agent名](例如 [GRANT:zhiwei])," + "该 Agent 会在看到标记后获得发言权。标记会显示在消息中。\n\n" f"[核心群 {room}] {nickname} 说: {body}" ) await self.call_hermes(ctx_body, room, is_group=True) @@ -266,15 +249,9 @@ class AgentBot(ClientXMPP): _grant_match = re.search(r'\[GRANT:(\w+)\]', reply) if _grant_match: _grant_name = _grant_match.group(1) - try: - _gdb = sqlite3.connect('/home/hmo/.hermes/state.db') - _gdb.execute("INSERT OR REPLACE INTO state_meta (key, value) VALUES ('coregroup_granted_speaker', ?)", (_grant_name,)) - _gdb.commit() - _gdb.close() - logging.info(f"🎤 Coordinator 授权 {_grant_name} 发言") - except Exception: - pass - reply = reply.replace(_grant_match.group(0), '').strip() + self._granted = _grant_name + logging.info(f"🎤 授权 {_grant_name} 发言(通过 XMPP 发送)") + # 不剥离标记,让其他 bot 从 XMPP 消息中解析 if msg_type == 'groupchat': self.send_message(mto=sender, mbody=reply, mtype='groupchat')