2026-10-05 05:43:26 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
"""prompt_envelope.py — wraps every dispatched job prompt so agents DO work.
|
|
|
|
|
|
|
|
|
|
Why: agents treated job DMs as informational and replied with prose; swarms and
|
|
|
|
|
timers never got created. The envelope puts an executable subagent-spawn tool
|
|
|
|
|
call at the TOP (before the task) and repeats it at the BOTTOM (after the task),
|
|
|
|
|
with a work-first mandate and explicit tool/curl surface in between.
|
|
|
|
|
|
|
|
|
|
Profiles tune the spawn recipe per job family; add new ones to PROFILES.
|
|
|
|
|
"""
|
|
|
|
|
import json
|
|
|
|
|
import re
|
2026-10-05 16:31:35 +00:00
|
|
|
import hashlib
|
2026-10-05 05:43:26 +00:00
|
|
|
|
2026-10-05 15:22:39 +00:00
|
|
|
BOX_API = "https://box.muse-dev.online/api/box"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _response_rule():
|
|
|
|
|
return (
|
2026-10-06 08:20:14 +00:00
|
|
|
"\nRESPONSE RULE: Act by EMITTING [TOOL ...] / [DM ...] directive lines verbatim in your reply"
|
|
|
|
|
" — you do not run them yourself. The Box runtime on bl executes each directive"
|
|
|
|
|
" (this works from containers with no box CLI or tmux socket) and posts the result back here."
|
|
|
|
|
" Background tmux commands work too when you have a shell."
|
2026-10-05 16:41:42 +00:00
|
|
|
" When complete, conclude your output with the [RESULT ...] line so the harvester records it.\n"
|
2026-10-05 15:22:39 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _box_surface_block(agent, job_name, job_id, target):
|
2026-10-05 16:41:42 +00:00
|
|
|
"""Clean runtime context block for the agent."""
|
2026-10-05 15:22:39 +00:00
|
|
|
header = (
|
|
|
|
|
"\n---- BOX RUNTIME ----\n"
|
|
|
|
|
"THREAD: " + str(target) + "\n"
|
|
|
|
|
"RUNTIME: https://box.muse-dev.online/\n"
|
|
|
|
|
"JOB: " + str(job_id) + "\n"
|
|
|
|
|
"AGENT: " + str(agent) + "\n"
|
|
|
|
|
)
|
2026-10-05 16:41:42 +00:00
|
|
|
return header + _response_rule()
|
|
|
|
|
|
2026-10-05 15:22:39 +00:00
|
|
|
|
2026-10-05 05:43:26 +00:00
|
|
|
UUID_RE = re.compile(r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")
|
|
|
|
|
|
|
|
|
|
# profile -> (spawn count, followup minutes, spawn task hint)
|
|
|
|
|
PROFILES = {
|
|
|
|
|
"pulse": (2, 30, "execute your scope's standing work: set timers, verify them, report per-slot verdicts"),
|
|
|
|
|
"health": (2, 60, "run the prescribed health gates read-only and report per-gate verdicts"),
|
|
|
|
|
"swarm": (2, 20, "sweep swarms and sidechats read-only and report stale or unarchived items"),
|
|
|
|
|
"work": (2, 15, "split the task above into two independent halves and complete each"),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def pick_profile(job_name):
|
|
|
|
|
n = job_name or ""
|
|
|
|
|
if n.startswith("autonomy-pulse"):
|
|
|
|
|
return "pulse"
|
|
|
|
|
if "health" in n:
|
|
|
|
|
return "health"
|
|
|
|
|
if "swarm" in n:
|
|
|
|
|
return "swarm"
|
|
|
|
|
return "work"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _tool(op, args):
|
2026-10-06 07:29:16 +00:00
|
|
|
# the harvester extracts JSON args with balanced-brace scanning, so
|
|
|
|
|
# ']' and nested objects/arrays inside args are safe
|
2026-10-05 05:43:26 +00:00
|
|
|
return "[TOOL %s %s]" % (op, json.dumps(args, separators=(", ", ": ")))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def spawn_call(job_id, job_name, profile):
|
|
|
|
|
count, _, hint = PROFILES[profile]
|
|
|
|
|
task = "Subagent for job %s (%s): %s." % (job_id, job_name, hint)
|
2026-10-06 20:02:48 +00:00
|
|
|
return _tool("swarm.spawn", {"count": count, "task": task[:900], "label": (job_name or "job")[:60]})
|
2026-10-06 07:29:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def dm_call(to, target, message):
|
|
|
|
|
return "[DM %s]" % json.dumps(
|
|
|
|
|
{"to": to, "target": target, "message": message[:900]},
|
|
|
|
|
separators=(", ", ": "))
|
|
|
|
|
|
|
|
|
|
|
2026-10-05 05:45:12 +00:00
|
|
|
def native_followup_call(job_id, job_name, profile, agent):
|
|
|
|
|
"""Muse-native one-shot cron (cron.create runonce) - bridged to followup.create."""
|
|
|
|
|
_, mins, _ = PROFILES[profile]
|
|
|
|
|
return _tool("cron.create", {
|
|
|
|
|
"kind": "runonce", "agent": agent, "in_m": mins,
|
|
|
|
|
"prompt": "Continue job %s (%s): verify with cron.runs and swarm.list then act or close." % (job_id, job_name)})
|
|
|
|
|
|
|
|
|
|
|
2026-10-05 05:43:26 +00:00
|
|
|
def followup_call(job_id, job_name, profile, agent):
|
|
|
|
|
_, mins, _ = PROFILES[profile]
|
|
|
|
|
return _tool("followup.create", {
|
|
|
|
|
"agent": agent, "in_m": mins,
|
|
|
|
|
"prompt": "Continue job %s (%s): check swarm results with swarm.list then act or close." % (job_id, job_name)})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def thread_url(target):
|
|
|
|
|
t = str(target)
|
|
|
|
|
return "https://box.muse-dev.online/%s/%s" % ("thread" if UUID_RE.fullmatch(t.lower()) else "sidechat", t)
|
|
|
|
|
|
|
|
|
|
|
2026-10-06 20:02:48 +00:00
|
|
|
def wrap(job_name, job_id, agent, target, rendered, include_kpi: bool = True):
|
2026-10-05 16:47:24 +00:00
|
|
|
"""Return the full DM body as a direct, authentic operator directive."""
|
2026-10-05 05:43:26 +00:00
|
|
|
profile = pick_profile(job_name)
|
|
|
|
|
spawn = spawn_call(job_id, job_name, profile)
|
2026-10-05 05:45:12 +00:00
|
|
|
follow = native_followup_call(job_id, job_name, profile, agent)
|
2026-10-05 16:31:35 +00:00
|
|
|
parts = job_id.split("-")
|
|
|
|
|
wo_id = parts[-1] if len(parts) > 1 and len(parts[-1]) >= 8 else hashlib.sha256(job_id.encode()).hexdigest()[:8]
|
|
|
|
|
session_name = f"work-{agent}-{wo_id}"
|
2026-10-06 20:02:48 +00:00
|
|
|
|
|
|
|
|
advisory_section = ""
|
|
|
|
|
if include_kpi:
|
|
|
|
|
try:
|
|
|
|
|
import kpi
|
|
|
|
|
advisory = kpi.get_live_advisory_block(agent)
|
|
|
|
|
if advisory:
|
|
|
|
|
advisory_section = f"\n{advisory}\n"
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
|
2026-10-05 05:43:26 +00:00
|
|
|
top = (
|
2026-10-05 16:47:24 +00:00
|
|
|
f"Operator Directive [ref:{wo_id}]:\n"
|
2026-10-09 23:13:43 +00:00
|
|
|
f"Persistent box runtime is on bl (/tmp/tmux-muse.sock). No worker session exists yet — create yours first: [TOOL tmux.new {{\"session\": \"{session_name}\", \"command\": \"bash\"}}].\n"
|
2026-10-05 16:47:24 +00:00
|
|
|
f" • Subagent assistance: {spawn}\n"
|
2026-10-06 20:02:48 +00:00
|
|
|
f" • Verification schedule: {follow}\n"
|
|
|
|
|
f"{advisory_section}\n"
|
2026-10-05 16:47:24 +00:00
|
|
|
"--- Task ---\n"
|
2026-10-05 05:43:26 +00:00
|
|
|
)
|
2026-10-06 20:02:48 +00:00
|
|
|
|
2026-10-05 05:43:26 +00:00
|
|
|
has_result = "[RESULT" in rendered
|
|
|
|
|
bottom = (
|
2026-10-05 16:47:24 +00:00
|
|
|
"\n--- End Task ---\n\n"
|
2026-10-09 23:13:43 +00:00
|
|
|
f"Worker convention: name your tmux session {session_name} when you create it, then inspect via box tmux capture {session_name} 30.\n"
|
|
|
|
|
"Flow in tmux: [TOOL flow.start {\"flow_id\": \"<id>\", \"command\": \"<cmd>\"}] | read delta: [TOOL flow.read {\"flow_id\": \"<id>\"}] | advance: [TOOL flow.send {\"flow_id\": \"<id>\", \"command\": \"...\"}].\n"
|
|
|
|
|
"Tools: flow.start, flow.read, flow.send, cron.create, health.check, swarm.spawn, dm.send, box.exec, tools.list.\n"
|
2026-10-06 07:29:16 +00:00
|
|
|
"Message a peer: [DM {\"to\": \"<agent>\", \"target\": \"<sidechat>\", \"message\": \"<text>\"}].\n"
|
2026-10-06 20:02:48 +00:00
|
|
|
"Query box: [TOOL box.exec {\"action\": \"<fleet-status|dm-log|job-get|...>\"}] — [TOOL tools.list {}] lists every op.\n"
|
2026-10-05 05:43:26 +00:00
|
|
|
)
|
|
|
|
|
if not has_result:
|
2026-10-05 16:47:24 +00:00
|
|
|
bottom += f"When complete, report your verdict: [RESULT {job_id}] OK: <summary of actions>\n"
|
2026-10-05 05:43:26 +00:00
|
|
|
else:
|
2026-10-05 16:47:24 +00:00
|
|
|
bottom += f"Conclude with your [RESULT {job_id}] line reporting outcomes.\n"
|
2026-10-05 05:43:26 +00:00
|
|
|
return top + rendered.strip() + "\n" + bottom
|
2026-10-05 16:47:24 +00:00
|
|
|
|
2026-10-05 20:18:46 +00:00
|
|
|
|
|
|
|
|
def wrap_subagent_task(job_id, task_text):
|
|
|
|
|
"""Format an authentic direct task assignment for a subagent worker without test-traffic meta tags."""
|
|
|
|
|
return (
|
|
|
|
|
f"Operator assignment for swarm slot {job_id}:\n\n"
|
|
|
|
|
f"Task:\n"
|
|
|
|
|
f"{task_text.strip()}\n\n"
|
|
|
|
|
f"Instructions:\n"
|
|
|
|
|
f"1. Carry out this task directly using your available tools.\n"
|
|
|
|
|
f"2. When finished, conclude your final response with your verdict line:\n"
|
|
|
|
|
f"[RESULT {job_id}] OK: <one-line summary of actions and outcome>\n"
|
|
|
|
|
f"(or [RESULT {job_id}] FAIL: <reason> if the task could not be completed)\n"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|