feat(prompts): work-first envelope with spawn/followup tool calls at top and bottom

This commit is contained in:
operator
2026-10-05 05:43:26 +00:00
parent dad33dcaa3
commit 74d093d259
3 changed files with 115 additions and 26 deletions
+4 -22
View File
@@ -528,28 +528,10 @@ def main():
"step_n": step_n, "step_n": step_n,
}) })
# Determine thread url / context for the runtime envelope # Work-first envelope: executable swarm.spawn/followup.create at TOP and BOTTOM
target_clean = str(target) # (see bin/prompt_envelope.py). Always applied, even if the template has its own [RESULT.
thread_url = f"https://box.muse-dev.online/thread/{target_clean}" if re.fullmatch(r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", target_clean.lower()) else f"https://box.muse-dev.online/sidechat/{target_clean}" import prompt_envelope
rendered = prompt_envelope.wrap(job_name, job_id, agent, target, rendered)
# Build active tool calling envelope for https://box.muse-dev.online/
tool_envelope = (
f"\n\n--- NetVM Runtime & Tools ({agent} on {target_clean}) ---\n"
f"Thread Console: {thread_url}\n"
f"Available Tools via [TOOL <op> <json_args>] or curl to https://box.muse-dev.online/exec:\n"
f" • Status: [TOOL health.check {{}}]\n"
f" • Service: [TOOL service.status {{\"unit\": \"board.service\"}}]\n"
f" • Follow-up: [TOOL followup.create {{\"in_m\": 10, \"prompt\": \"check progress\"}}]\n"
f" • Swarm: [TOOL swarm.spawn {{\"count\": 2, \"task\": \"parallel work\"}}]\n"
f"Direct Curl (Agent Bearer Auth):\n"
f" curl -sk -X POST https://box.muse-dev.online/exec -H \"Authorization: Bearer <token>\" "
f"-H \"Content-Type: application/json\" -d '{{\"op\":\"<op>\",\"args\":{{...}}}}'\n\n"
f"When finished, end your response with:\n"
f"[RESULT {job_id}] <OK|FAILED>: <summary of output>"
)
if "[RESULT" not in rendered:
rendered = rendered.rstrip() + tool_envelope
# Format as JOB DM # Format as JOB DM
dm_message = f"[JOB {job_id}] {rendered}" dm_message = f"[JOB {job_id}] {rendered}"
+91
View File
@@ -0,0 +1,91 @@
#!/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
BOX_EXEC = "https://box.muse-dev.online/exec"
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):
# no ']' inside the JSON: the harvester's [TOOL ...] regex stops at the first one
return "[TOOL %s %s]" % (op, json.dumps(args, separators=(", ", ": ")))
def spawn_call(job_id, job_name, profile):
count, _, hint = PROFILES[profile]
# no brackets in the task text: the harvester's [TOOL ...] regex stops at the first ']'
task = "Subagent for job %s (%s): %s." % (job_id, job_name, hint)
return _tool("swarm.spawn", {"count": count, "task": task[:900], "label": (job_name or "job")[:60]})
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)
def wrap(job_name, job_id, agent, target, rendered):
"""Return the full DM body (without the [JOB id] prefix)."""
profile = pick_profile(job_name)
spawn = spawn_call(job_id, job_name, profile)
follow = followup_call(job_id, job_name, profile, agent)
top = (
"WORK ORDER - ACTION REQUIRED, NOT INFORMATIONAL.\n"
"Your FIRST output must be tool calls, not prose. Start now:\n"
" 1) %s\n"
" 2) %s\n"
"Each tool call returns a result message; keep going until the task is done.\n"
"---- TASK ----\n" % (spawn, follow)
)
has_result = "[RESULT" in rendered
bottom = (
"\n---- END TASK ----\n"
"REMINDER (importance: critical): work is only real if a tool call ran. "
"If you have not yet spawned subagents or set a follow-up timer, do it now:\n"
" %s\n"
" %s\n"
"Other tools: [TOOL health.check {}] [TOOL swarm.list {}] [TOOL swarm.status {\"swarm_id\": \"<id>\"}] "
"[TOOL swarm.results {\"swarm_id\": \"<id>\"}] [TOOL quality.check {}]\n"
"Direct: curl -sk -X POST %s -H \"Authorization: Bearer <token>\" "
"-H \"Content-Type: application/json\" -d '{\"op\":\"<op>\",\"args\":{...}}'\n"
"Thread: %s\n" % (spawn, follow, BOX_EXEC, thread_url(target))
)
if not has_result:
bottom += "Close with: [RESULT %s] <OK|FAILED>: <summary of tool outputs>\n" % job_id
else:
bottom += "Close using the [RESULT ...] line specified in the task, summarising tool outputs.\n"
return top + rendered.strip() + "\n" + bottom
+20 -4
View File
@@ -163,7 +163,16 @@ def parse_tool_calls(text):
except Exception: except Exception:
pass pass
return calls # De-duplicate identical calls within one message (envelope repeats the spawn
# call at top and bottom; an agent echoing both must not run it twice).
seen, unique = set(), []
for op, args in calls:
key = (op, json.dumps(args, sort_keys=True, default=str))
if key in seen:
continue
seen.add(key)
unique.append((op, args))
return unique
def execute_agent_tool(agent, op, args, timeout=30): def execute_agent_tool(agent, op, args, timeout=30):
@@ -1065,12 +1074,19 @@ def maybe_nudge_untagged_sidechat(agent, thread_id, thread_name, mid, text, dry_
# 1st turn: Strict rejection and tool invocation prompt # 1st turn: Strict rejection and tool invocation prompt
if n_count == 0: if n_count == 0:
thread_url = f"https://box.muse-dev.online/thread/{thread_id}" thread_url = f"https://box.muse-dev.online/thread/{thread_id}"
try:
import prompt_envelope
_spawn = prompt_envelope.spawn_call(
matching_job_id, matching_job_id, prompt_envelope.pick_profile(matching_job_id))
except Exception:
_spawn = '[TOOL swarm.spawn {"count": 2, "task": "continue the job work"}]'
nudge_msg = ( nudge_msg = (
f"{_spawn}\n"
f"[STRICT ENFORCEMENT: Conversational commentary is rejected. Work requires active execution.]\n" f"[STRICT ENFORCEMENT: Conversational commentary is rejected. Work requires active execution.]\n"
f"Thread Console: {thread_url}\n" f"Thread Console: {thread_url}\n"
f"You must emit an executable tool call: [TOOL <op> <args>] or curl command against https://box.muse-dev.online/exec\n" f"Emit executable tool calls now: [TOOL <op> <args>] or curl against https://box.muse-dev.online/exec\n"
f"Example: [TOOL service.status {{\"unit\": \"board.service\"}}] or [TOOL followup.create {{\"in_m\": 10, \"prompt\": \"continue\"}}]\n" f"When all operations are finished, close strictly with [RESULT {matching_job_id}] <outcome>.\n"
f"When all operations are finished, close strictly with [RESULT {matching_job_id}] <outcome>." f"{_spawn}"
) )
try: try:
import muse_hybrid import muse_hybrid