feat(hybrid-gateway): integrate muse-cli with Cloudflare netns isolation, symmetric sidechat routing, and 646-pip sync unblock
This commit is contained in:
+61
-24
@@ -1174,24 +1174,38 @@ def cmd_dm_files(args):
|
||||
# ---------------------------------------------------------------------------
|
||||
def cmd_thread_list(args):
|
||||
agent = args.agent
|
||||
cmd = ["python3", str(BIN_DIR / "box-chat.py"), "thread-list", agent]
|
||||
res = subprocess.run(cmd, capture_output=True, text=True)
|
||||
|
||||
threads = []
|
||||
|
||||
# Fast path: try fast headless gateway via muse_hybrid (isolated per-node WARP egress)
|
||||
try:
|
||||
data = json.loads(res.stdout)
|
||||
import muse_hybrid
|
||||
gw_threads, gw_err = muse_hybrid.get_threads(agent)
|
||||
if gw_threads and not gw_err:
|
||||
for t in gw_threads:
|
||||
threads.append({
|
||||
"id": t.get("session_id", ""),
|
||||
"kind": "thread" if t.get("thread") else "chat",
|
||||
"title": t.get("title") or "(no title)",
|
||||
"participants": [agent],
|
||||
"last_message_at": t.get("updated", "")
|
||||
})
|
||||
except Exception:
|
||||
print(c_red("Failed to parse box-chat.py response:") + f"\n{res.stdout}\n{res.stderr}")
|
||||
return
|
||||
pass
|
||||
|
||||
# Fallback to box-chat.py / CDP if gateway returned no threads
|
||||
if not threads:
|
||||
cmd = ["python3", str(BIN_DIR / "box-chat.py"), "thread-list", agent]
|
||||
res = subprocess.run(cmd, capture_output=True, text=True)
|
||||
try:
|
||||
data = json.loads(res.stdout)
|
||||
threads = data.get("threads", []) if data.get("ok") else []
|
||||
except Exception:
|
||||
threads = []
|
||||
|
||||
if args.json:
|
||||
print(json.dumps(data, indent=2))
|
||||
print(json.dumps({"ok": True, "threads": threads}, indent=2))
|
||||
return
|
||||
|
||||
if not data.get("ok"):
|
||||
print(c_red(f"Error fetching threads for {agent}: {data.get('error', 'unknown error')}"))
|
||||
return
|
||||
|
||||
threads = data.get("threads", [])
|
||||
print("\n" + c_bold(f"=== ACTIVE THREADS FOR {agent.upper()} ({len(threads)}) ===") + "\n")
|
||||
|
||||
headers = ["ID / UUID", "KIND", "TITLE", "PARTICIPANTS", "LAST ACTIVE"]
|
||||
@@ -1213,25 +1227,39 @@ def cmd_thread_view(args):
|
||||
agent = args.agent
|
||||
thread_id = args.thread_id
|
||||
limit = getattr(args, "limit", 15)
|
||||
messages = []
|
||||
|
||||
cmd = ["python3", str(BIN_DIR / "box-chat.py"), "thread-messages", agent, thread_id, "--limit", str(limit)]
|
||||
res = subprocess.run(cmd, capture_output=True, text=True)
|
||||
|
||||
# Fast path: try fast headless gateway via muse_hybrid (isolated per-node WARP egress)
|
||||
try:
|
||||
data = json.loads(res.stdout)
|
||||
import muse_hybrid
|
||||
gw_msgs, gw_err = muse_hybrid.get_history(agent, thread_id=thread_id, limit=limit)
|
||||
if gw_msgs and not gw_err:
|
||||
for m in gw_msgs:
|
||||
role = m.get("role", "unknown")
|
||||
messages.append({
|
||||
"from": {"name": role, "role": role},
|
||||
"text": m.get("text", "")
|
||||
})
|
||||
except Exception:
|
||||
print(c_red("Failed to parse box-chat.py response:") + f"\n{res.stdout}\n{res.stderr}")
|
||||
return
|
||||
pass
|
||||
|
||||
# Fallback to box-chat.py / CDP if gateway returned no messages
|
||||
if not messages:
|
||||
cmd = ["python3", str(BIN_DIR / "box-chat.py"), "thread-messages", agent, thread_id, "--limit", str(limit)]
|
||||
res = subprocess.run(cmd, capture_output=True, text=True)
|
||||
try:
|
||||
data = json.loads(res.stdout)
|
||||
messages = data.get("messages", []) if data.get("ok") else []
|
||||
except Exception:
|
||||
messages = []
|
||||
if not messages:
|
||||
print(c_red(f"Error viewing thread {thread_id}: no messages returned"))
|
||||
return
|
||||
|
||||
if args.json:
|
||||
print(json.dumps(data, indent=2))
|
||||
print(json.dumps({"ok": True, "messages": messages}, indent=2))
|
||||
return
|
||||
|
||||
if not data.get("ok"):
|
||||
print(c_red(f"Error viewing thread {thread_id}: {data.get('error', 'unknown error')}"))
|
||||
return
|
||||
|
||||
messages = data.get("messages", [])
|
||||
print("\n" + c_bold(f"=== THREAD {thread_id} ({agent}) — {len(messages)} messages ===") + "\n")
|
||||
|
||||
for msg in messages:
|
||||
@@ -3280,6 +3308,11 @@ def build_parser():
|
||||
p_va_rb.add_argument("name", help="Variable name")
|
||||
p_va_rb.add_argument("--revision", default=None, help="Revision step (int) or timestamp")
|
||||
|
||||
# Domain: muse (fast headless gateway via muse-cli-node with isolated per-node Cloudflare WARP egress)
|
||||
p_muse = subparsers.add_parser("muse", parents=[common], help="Direct headless gateway client (muse-cli-node)")
|
||||
p_muse.add_argument("node", choices=VALID_NODES, help="Target agent node")
|
||||
p_muse.add_argument("muse_args", nargs=argparse.REMAINDER, help="Arguments passed directly to muse-cli-node")
|
||||
|
||||
return parser
|
||||
|
||||
def main():
|
||||
@@ -3446,6 +3479,10 @@ def main():
|
||||
cmd_loop_strat(args)
|
||||
elif args.domain == "vars":
|
||||
cmd_loop_vars(args)
|
||||
elif args.domain == "muse":
|
||||
cmd = [str(BIN_DIR / "muse-cli-node"), args.node] + (args.muse_args or [])
|
||||
res = subprocess.run(cmd)
|
||||
sys.exit(res.returncode)
|
||||
else:
|
||||
parser.print_help()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user