feat(relay): add subagent spawn, thread tools, and container box client

- Upgrade exec-constrained.py with subagent.spawn, thread.list, thread.view, pipeline.run ops
- Grant full ops permissions to all fleet agent identities (646, pip, muse, opm)
- Implement bin/box-relay.sh zero-dependency client supporting bearer and SSH signature auth
- Add fast hybrid gateway path to dm.py for sub-2s verified deliveries
- Fix wait=0 handling in super-cli.py subagent deployments
- Add hourly check-in jobs and scheduler for 646, pip, muse
- Document agent tooling and relay APIs in docs/AGENT-TOOLING.md
This commit is contained in:
operator
2026-10-04 23:30:18 +00:00
parent c1545fe6db
commit d6ca600394
16 changed files with 953 additions and 15 deletions
+74 -1
View File
@@ -1246,8 +1246,8 @@ def cmd_thread_view(args):
# 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:
res = subprocess.run(cmd, capture_output=True, text=True, timeout=15)
data = json.loads(res.stdout)
messages = data.get("messages", []) if data.get("ok") else []
except Exception:
@@ -2502,6 +2502,63 @@ def cmd_pipeline_prune(args):
print(json.dumps({"pruned": pruned, "count": len(pruned)}, indent=2))
# ---------------------------------------------------------------------------
# Domain: DEPLOY (Multi-Agent Pipelines, Subagent Spawning, and Oversight)
# ---------------------------------------------------------------------------
def cmd_deploy(args):
action = getattr(args, "action", None)
if action == "subagent":
agent = args.agent
title = args.title or "subagent-task"
prompt = args.prompt
wait_val = getattr(args, "wait", 30)
wait = 30 if wait_val is None else int(wait_val)
print(c_bold(f"\n=== DEPLOYING SUBAGENT ON [{agent}] ==="))
print(f" Agent: {c_cyan(agent)}")
print(f" Title: {c_yellow(title)}")
print(f" Prompt: {c_dim(prompt[:90])}...\n")
import muse_hybrid
res, err = muse_hybrid.start_session(agent, title=title)
if err or not res:
print(c_err(f"✖ Failed to spawn subagent session: {err}"), file=sys.stderr)
sys.exit(1)
session_id = res.get("session_id")
print(c_green(f"✔ Subagent session spawned: {session_id}"))
if prompt:
print(f" Dispatching task prompt to subagent (waiting up to {wait}s)...")
send_res, send_err = muse_hybrid.send_message(agent, prompt, thread_id=session_id, wait=wait)
if send_err:
print(c_warn(f"Notice: {send_err}"))
else:
print(c_green("✔ Task prompt delivered."))
# Fetch fresh history to show assistant's initial work
msgs, _ = muse_hybrid.get_history(agent, thread_id=session_id, limit=5)
if msgs:
for m in msgs:
role = m.get("role")
if role == "assistant":
print(f"\n{c_bold('--- Subagent Response ---')}\n{m.get('text')}\n")
print(f" Oversee anytime with: {c_cyan(f'box thread view {agent} {session_id}')}\n")
return
# Pipeline deployment
pipe_name = getattr(args, "name", None)
if not pipe_name:
print(c_err("Error: Specify pipeline name (e.g. box deploy pipeline pipe-demo-step1)"), file=sys.stderr)
sys.exit(1)
args.name = pipe_name
cmd_pipeline_run(args)
# ---------------------------------------------------------------------------
# Domain: LOOP (Intrinsic Loop Strategy, Health, Break Taxonomy, and Control)
# ---------------------------------------------------------------------------
@@ -3333,6 +3390,20 @@ 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: deploy (Deploy multi-agent pipelines or subagent tasks with oversight)
p_deploy = subparsers.add_parser("deploy", parents=[common], help="Deploy multi-agent task or pipeline across nodes with live oversight")
deploy_sub = p_deploy.add_subparsers(dest="action")
p_dep_pipe = deploy_sub.add_parser("pipeline", parents=[common], help="Deploy multi-agent pipeline")
p_dep_pipe.add_argument("name", help="Pipeline root job name (e.g. pipe-demo-step1)")
p_dep_pipe.add_argument("--dry-run", action="store_true", help="Simulate pipeline without sending DMs")
p_dep_sub = deploy_sub.add_parser("subagent", parents=[common], help="Spawn sub-agent session and dispatch task")
p_dep_sub.add_argument("--agent", required=True, choices=VALID_NODES, help="Agent node to spawn subagent on")
p_dep_sub.add_argument("--title", default="subagent-task", help="Title for the subagent session")
p_dep_sub.add_argument("prompt", help="Task prompt for the subagent")
p_dep_sub.add_argument("--wait", type=int, default=30, help="Seconds to wait for subagent response")
# 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")
@@ -3506,6 +3577,8 @@ def main():
cmd_loop_strat(args)
elif args.domain == "vars":
cmd_loop_vars(args)
elif args.domain == "deploy":
cmd_deploy(args)
elif args.domain == "muse":
cmd = [str(BIN_DIR / "muse-cli-node"), args.node] + (args.muse_args or [])
res = subprocess.run(cmd)