feat(swarm): launch live swarm worker daemon under tmux supervisor

This commit is contained in:
operator
2026-10-05 17:29:16 +00:00
parent 7fc15eb127
commit 9e833d0c4b
7 changed files with 829 additions and 0 deletions
+87
View File
@@ -0,0 +1,87 @@
#!/usr/bin/env python3
"""Swarm worker -> main-loop visibility bridge (Bridge Builder 5/5).
After the worker records a slot result via `box swarm-report` (see
reporter.py), this posts a short human-readable completion note to the
slot's own sidechat. The note deliberately carries NO `[JOB ` tag, so
self_main_loop.py's check_sidechats() does not filter it: the next
main-loop tick picks it up, includes it in the agent's digest, and the
completion becomes visible in the same surface as everything else.
That is the "answering via the main loop" path.
Design doc: bin/swarm_worker/mainloop-bridge.md
Runs on bl. Never auto-wired into any loop; call explicitly from the
worker daemon after post_result() succeeds. Dry-run mode posts nothing.
"""
import subprocess
import sys
BIN = "/home/super/Projects/NetVM/bin"
DM_PY = BIN + "/dm.py"
NOTE_CHARS = 200
def notify_via_mainloop(swarm_id, slot_index, message, worker_id="swarm-worker",
dry_run=False):
"""Post a swarm-slot completion note visible to the main loop.
Args:
swarm_id: e.g. "sw-20261005-151307-a222"
slot_index: int slot number
message: human-readable summary (first NOTE_CHARS chars used)
worker_id: sender identity for dm.py --agent
dry_run: if True, print what WOULD be sent without sending.
Returns:
True on success (or dry-run), False on failure (logged, not raised).
"""
target_name = "sw-%s-s%s" % (swarm_id, slot_index)
summary = (message or "").strip().replace("\n", " ")[:NOTE_CHARS]
note = "[SWARM-DONE %s/%s] %s" % (swarm_id, slot_index, summary)
try:
sys.path.insert(0, BIN)
import dm
uuid = dm.resolve_sidechat_target(target_name)
except Exception as e:
print("notify_via_mainloop: target resolve failed for %s: %s"
% (target_name, e), file=sys.stderr)
return False
if not uuid:
print("notify_via_mainloop: no UUID for %s" % target_name,
file=sys.stderr)
return False
cmd = [sys.executable, DM_PY, "send",
"--agent", worker_id,
"--to", worker_id,
"--target", uuid,
note]
if dry_run:
print("DRY-RUN would run: %s" % " ".join(cmd))
return True
try:
r = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
except Exception as e:
print("notify_via_mainloop: dm.py exec failed: %s" % e,
file=sys.stderr)
return False
if r.returncode != 0:
tail = ((r.stderr or "") + (r.stdout or "")).strip()[-300:]
print("notify_via_mainloop: dm.py rc=%d: %s" % (r.returncode, tail),
file=sys.stderr)
return False
return True
if __name__ == "__main__":
live = "--live" in sys.argv
args = [a for a in sys.argv[1:] if a != "--live"]
if len(args) < 3:
print("usage: mainloop_notify.py <swarm-id> <slot> \"<message>\" [--live]")
print("default is DRY-RUN (posts nothing).")
sys.exit(2)
ok = notify_via_mainloop(args[0], args[1], args[2], dry_run=not live)
print("notified" if ok else "FAILED")