mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-08 10:47:44 +02:00
[eric] workflows: add EditWorkflowStep + TestWorkflow MCP tools for Edit Agent
This commit is contained in:
@@ -122,6 +122,43 @@ TOOLS = [
|
||||
"required": ["workflow_id"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "EditWorkflowStep",
|
||||
"description": (
|
||||
"Edit a single step's prompt text on an existing workflow. Use "
|
||||
"when the user has accepted a proposed change during an Edit "
|
||||
"Agent conversation; the new prompt replaces the existing one "
|
||||
"and persists immediately. The next scheduled run uses the new "
|
||||
"version. Always confirm the change with the user before "
|
||||
"calling this; AskUserQuestion FIRST if there is any ambiguity."
|
||||
),
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"workflow_id": {"type": "string", "description": "The workflow to edit."},
|
||||
"step_idx": {"type": "integer", "description": "0-based index of the step to modify."},
|
||||
"new_text": {"type": "string", "description": "Full replacement prompt text for the step."},
|
||||
},
|
||||
"required": ["workflow_id", "step_idx", "new_text"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "TestWorkflow",
|
||||
"description": (
|
||||
"Spawn a sibling Test Agent that runs the workflow end-to-end "
|
||||
"(with the latest persisted steps) so the user can watch it "
|
||||
"work. Use after editing a step to verify the change. The Test "
|
||||
"Agent renders as a sibling card on the dashboard with a "
|
||||
"'Testing' arrow chip linking back to this workflow."
|
||||
),
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"workflow_id": {"type": "string", "description": "The workflow to test."},
|
||||
},
|
||||
"required": ["workflow_id"],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@@ -286,6 +323,42 @@ def _err(text: str) -> dict:
|
||||
return {"content": [{"type": "text", "text": f"Error: {text}"}], "isError": True}
|
||||
|
||||
|
||||
def handle_edit_step(args: dict) -> dict:
|
||||
wid = args.get("workflow_id") or ""
|
||||
if not wid:
|
||||
return _err("workflow_id is required.")
|
||||
try:
|
||||
idx = int(args.get("step_idx"))
|
||||
except (TypeError, ValueError):
|
||||
return _err("step_idx must be an integer.")
|
||||
new_text = (args.get("new_text") or "").strip()
|
||||
if not new_text:
|
||||
return _err("new_text is required.")
|
||||
cur = _call("GET", f"/{wid}")
|
||||
if "_error" in cur:
|
||||
return _err(cur["_error"])
|
||||
steps = cur.get("steps") or []
|
||||
if idx < 0 or idx >= len(steps):
|
||||
return _err(f"step_idx {idx} out of range (workflow has {len(steps)} steps).")
|
||||
new_steps = list(steps)
|
||||
new_steps[idx] = {**new_steps[idx], "text": new_text}
|
||||
r = _call("PATCH", f"/{wid}", {"steps": new_steps})
|
||||
if "_error" in r:
|
||||
return _err(r["_error"])
|
||||
return _ok(f"Step {idx + 1} updated. The next run uses the new prompt.")
|
||||
|
||||
|
||||
def handle_test_workflow(args: dict) -> dict:
|
||||
wid = args.get("workflow_id") or ""
|
||||
if not wid:
|
||||
return _err("workflow_id is required.")
|
||||
r = _call("POST", f"/{wid}/test-run", {})
|
||||
if "_error" in r:
|
||||
return _err(r["_error"])
|
||||
sid = r.get("session_id", "")
|
||||
return _ok(f"Test Agent spawned (session {sid[:8]}...). It runs the latest workflow on the dashboard with a Testing arrow chip.")
|
||||
|
||||
|
||||
HANDLERS = {
|
||||
"ScheduleWorkflow": handle_schedule_workflow,
|
||||
"ListScheduledWorkflows": handle_list,
|
||||
@@ -294,6 +367,8 @@ HANDLERS = {
|
||||
"PauseAllWorkflows": handle_pause_all,
|
||||
"ResumeAllWorkflows": handle_resume_all,
|
||||
"RunWorkflowNow": handle_run_now,
|
||||
"EditWorkflowStep": handle_edit_step,
|
||||
"TestWorkflow": handle_test_workflow,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -552,18 +552,23 @@ async def edit_agent_session(workflow_id: str):
|
||||
from backend.apps.agents.agent_manager import agent_manager
|
||||
steps_lines = "\n".join(f"{i+1}. {(s.label or '').strip() or (s.text or '')[:60]}\n Prompt: {s.text}" for i, s in enumerate(wf.steps))
|
||||
system_prompt = (
|
||||
f"You are the Edit Agent for the user's saved workflow \"{wf.title}\". "
|
||||
f"Help the user iterate on it. The workflow's purpose: {wf.description or '(unspecified)'}.\n\n"
|
||||
f"You are the Edit Agent for the user's saved workflow \"{wf.title}\" "
|
||||
f"(id: {wf.id}). Help the user iterate on it. The workflow's purpose: "
|
||||
f"{wf.description or '(unspecified)'}.\n\n"
|
||||
f"Current steps:\n{steps_lines}\n\n"
|
||||
"When the user asks for a change, briefly confirm what you'll do, "
|
||||
"then either edit the prompt text or test the workflow before suggesting "
|
||||
"they Save. You have access to the full tool surface (Read, Edit, Write, "
|
||||
"Bash, MCP servers, etc.) so you can run searches, look at files, or "
|
||||
"activate integrations the user already has connected. To test the workflow "
|
||||
"end-to-end, call TestWorkflow (it spawns a sibling Test Agent that runs "
|
||||
"the latest draft). When you've made a concrete prompt change you're "
|
||||
"confident about, tell the user clearly so they can apply it via the Save "
|
||||
"button at the top of the card."
|
||||
"How to work:\n"
|
||||
"1. When the user describes a change, briefly confirm what you'll do.\n"
|
||||
"2. If you need to look at files / search / activate an MCP / etc. to "
|
||||
"verify your idea, use your tools.\n"
|
||||
"3. Call EditWorkflowStep(workflow_id, step_idx, new_text) to apply a "
|
||||
"prompt change to a specific step. The change persists immediately. "
|
||||
"Confirm with the user via AskUserQuestion FIRST if there's any "
|
||||
"ambiguity about what they want.\n"
|
||||
"4. Call TestWorkflow(workflow_id) to spawn a sibling Test Agent that "
|
||||
"runs the latest version end-to-end. Use this after a change to verify "
|
||||
"it works.\n\n"
|
||||
"Be brief in your replies. Don't restate the whole workflow back; the "
|
||||
"user can see it. Just confirm what changed and what you're doing."
|
||||
)
|
||||
config = AgentConfig(
|
||||
name=f"Edit Agent: {wf.title}",
|
||||
|
||||
Reference in New Issue
Block a user