feat(swarm-worker): dispatch prose swarm slots to ephemeral Muse subagents
- daemon: route non-shell slot tasks to a fresh subagent session on dev/def/muse via muse_hybrid; add bin/ to sys.path so muse_hybrid/prompt_envelope import under the tmux supervisor - prompt_envelope: add wrap_subagent_task() - plain task assignment without [TOOL tmux/swarm/cron] meta tags (subagents refused those as relayed test traffic) - box-ctl/reporter: swarm-attach accepts optional session-id, stored as slot.subagent_session_id - executor: _looks_like_shell requires an existing executable (prose like 'verify ...' no longer misread as shell) - poller: pick up pending swarms as well as running - response-harvester: monitor running slot subagent sessions from swarms.json, allow '/' in RESULT/VERB job ids, archive ephemeral threads on any verdict (OK or FAIL), reap slot sessions for terminal swarms
This commit is contained in:
@@ -97,6 +97,60 @@ def post_result(swarm_id, slot_index, result_dict, dry_run=False):
|
||||
swarm_id, slot_index, str(resp)[:500])
|
||||
return False
|
||||
|
||||
def attach_slot(swarm_id, slot_index, agent_id, session_id=None, dry_run=False):
|
||||
"""Claim/attach a swarm slot to an agent in box state.
|
||||
|
||||
Args:
|
||||
swarm_id: e.g. "sw-20261005-151307-a222"
|
||||
slot_index: int slot number
|
||||
agent_id: agent string, e.g. "dev"
|
||||
session_id: optional subagent session ID string
|
||||
dry_run: if True, simulate attach without changing state.
|
||||
|
||||
Returns:
|
||||
True on success, False on failure.
|
||||
"""
|
||||
if dry_run:
|
||||
print("DRY-RUN would run: %s swarm-attach %s %s %s %s"
|
||||
% (BOX_CTL, swarm_id, slot_index, agent_id, session_id or ""))
|
||||
return True
|
||||
|
||||
cmd = [
|
||||
sys.executable, BOX_CTL, "swarm-attach",
|
||||
str(swarm_id), str(slot_index), str(agent_id),
|
||||
]
|
||||
if session_id:
|
||||
cmd.append(str(session_id))
|
||||
|
||||
try:
|
||||
proc = subprocess.run(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
timeout=30,
|
||||
)
|
||||
except Exception as e:
|
||||
log.error("attach_slot %s/%s failed to invoke box-ctl: %s",
|
||||
swarm_id, slot_index, e)
|
||||
return False
|
||||
|
||||
if proc.returncode != 0:
|
||||
err = proc.stderr.decode("utf-8", "replace")[:500]
|
||||
log.error("attach_slot %s/%s box-ctl rc=%d: %s",
|
||||
swarm_id, slot_index, proc.returncode, err)
|
||||
return False
|
||||
|
||||
try:
|
||||
resp = json.loads(proc.stdout.decode("utf-8", "replace"))
|
||||
except ValueError:
|
||||
log.error("attach_slot %s/%s: box-ctl returned non-JSON output",
|
||||
swarm_id, slot_index)
|
||||
return False
|
||||
|
||||
if not resp.get("ok"):
|
||||
log.error("attach_slot %s/%s: box-ctl ok=false: %s",
|
||||
swarm_id, slot_index, str(resp)[:500])
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user