#!/usr/bin/env python3 """ openclaw-bridge.py — Hermes↔OpenClaw 智能桥接 ============================================== 让 Hermes(小唯 A06)能够: 1. 向 OpenClaw 指定 agent 发送消息 2. 读取 OpenClaw agent 的回复 3. 在 织忆 中记录跨系统通信 用法: # 向 A02 铁锋发消息 python3 openclaw-bridge.py send a02 "检查服务器磁盘空间" # 向 A01 小雪发消息 python3 openclaw-bridge.py send main "帮我整理今天的记忆" # 读取指定 agent 最近的回复 python3 openclaw-bridge.py read main --limit 5 # 查看所有 agent 健康状态 python3 openclaw-bridge.py status # 列出 织忆 中的跨系统记录 python3 openclaw-bridge.py history --limit 10 """ import argparse import json import os import subprocess import urllib.request OPENCLAW = "/home/muc/nodejs/node-v24.16.0-linux-x64/bin/openclaw" ZHIYI_URL = "http://127.0.0.1:7821/api/v1/commit" ZHIYI_RECALL = "http://127.0.0.1:7821/api/v1/recall" ZHIYI_KEY = os.environ.get("ZHIYI_API_KEY", "zhiyi-dev-key-2026") AGENTS = { "main": "A01小雪", "a02": "A02铁锋", "a03": "A03墨文", "a04": "A04卫安", "a05": "A05蓝图", } def shell_list(cmd_list, timeout=30): """执行命令(列表参数,防注入)""" try: r = subprocess.run(cmd_list, capture_output=True, text=True, timeout=timeout) return r.stdout, r.stderr, r.returncode except subprocess.TimeoutExpired: return "", "timeout", -1 def zhiyi_log(action, agent, content): """记录跨系统通信到织忆,失败时输出日志 2026-09-07 质量门槛(t_9316bf56): status/健康检查类动作不写织忆(731条刷屏重复根因), 短内容(<20字)也不写——碎片无记忆价值,污染 recall 与蒸馏质量。 """ if action == "status" or content is None: return # 健康检查无记忆价值,写=刷屏(08-17/18 曾产生 731 条完全重复) if len(str(content).strip()) < 20: return # 碎片过滤 agent_name = AGENTS.get(agent, agent) payload = json.dumps({ "content": f"小唯↔{agent_name} 桥接: {action} | {content[:200]}", "category": "distilled", "agent_id": "a06" }).encode() try: req = urllib.request.Request(ZHIYI_URL, data=payload, headers={"X-API-Key": ZHIYI_KEY, "Content-Type": "application/json"}) urllib.request.urlopen(req, timeout=5) except Exception as e: print(f"[bridge] ⚠ 织忆日志写入失败: {e}", file=__import__('sys').stderr) def cmd_send(agent, message): """向 OpenClaw agent 发送消息""" agent_name = AGENTS.get(agent, agent) print(f"📤 → {agent_name}: {message[:80]}...") # 用列表参数替代 shell 字符串拼接 stdout, stderr, rc = shell_list( [OPENCLAW, "chat", "--session", f"session://{agent}", "--input", message], timeout=60 ) if rc == 0: print(f"✅ 已发送至 {agent_name}") zhiyi_log("send", agent, f"发送消息: {message[:200]}") else: print(f"⚠️ CLI 发送失败({stderr[:50]}), 走织忆中转") zhiyi_log("send_queued", agent, f"排队消息: {message[:200]}") print(f"ℹ️ 消息已存织忆, {agent_name} 下次读取织忆时可获取") return rc def cmd_read(agent, limit=5): """读取 agent 最近的会话""" agent_name = AGENTS.get(agent, agent) print(f"📖 ← {agent_name} (最近{limit}条)") stdout, stderr, rc = shell_list( [OPENCLAW, "session", "list", "--agent", agent, "--limit", str(limit)], timeout=15 ) if rc == 0 and stdout.strip(): print(stdout[:2000]) else: if stderr.strip(): print(f"ℹ️ 诊断: {stderr.strip()[:100]}") print(f"ℹ️ {agent_name} 暂无新输出") return rc def cmd_status(): """查看所有 agent 健康状态""" print("🔍 OpenClaw Agent 健康检查") print("=" * 40) for agent_id, name in AGENTS.items(): # 用 openclaw agent (不加 status) 检查是否能路由 stdout, stderr, rc = shell_list( [OPENCLAW, "agent", "--agent", agent_id, "--help"], timeout=10 ) stderr_lower = stderr.lower() if rc == 0 or "registered" in stderr_lower or "plugins" in stderr_lower: print(f" {name} ({agent_id}): ✅ 已配置") else: err = stderr.strip()[:40] if stderr.strip() else f"exit={rc}" print(f" {name} ({agent_id}): ❌ {err}") print("=" * 40) zhiyi_log("status", "all", "健康检查完成") def cmd_history(limit=10): """从织忆读取跨系统通信历史""" payload = json.dumps({"query": "小唯↔ 桥接", "top_k": limit}).encode() req = urllib.request.Request(ZHIYI_RECALL, data=payload, headers={"X-API-Key": ZHIYI_KEY, "Content-Type": "application/json"}) try: resp = urllib.request.urlopen(req, timeout=10) data = json.loads(resp.read()) results = data.get("results", []) print(f"📋 桥接历史 (最近{len(results)}条):") for r in results: print(f" • {r.get('content','')[:120]}") except Exception as e: print(f"⚠️ 读取织忆失败: {e}", file=__import__('sys').stderr) def main(): parser = argparse.ArgumentParser(description="Hermes↔OpenClaw 桥接") sub = parser.add_subparsers(dest="command") p_send = sub.add_parser("send", help="向 agent 发消息") p_send.add_argument("agent", choices=list(AGENTS.keys()) + ["all"]) p_send.add_argument("message", help="消息内容") p_read = sub.add_parser("read", help="读取 agent 输出") p_read.add_argument("agent", choices=list(AGENTS.keys())) p_read.add_argument("--limit", type=int, default=5) sub.add_parser("status", help="健康检查") p_hist = sub.add_parser("history", help="通信历史") p_hist.add_argument("--limit", type=int, default=10) args = parser.parse_args() if args.command == "send": if args.agent == "all": for a in AGENTS: cmd_send(a, args.message) else: cmd_send(args.agent, args.message) elif args.command == "read": cmd_read(args.agent, args.limit) elif args.command == "status": cmd_status() elif args.command == "history": cmd_history(args.limit) else: parser.print_help() if __name__ == "__main__": main()