[eric] workflows: add EditWorkflowStep + TestWorkflow MCP tools for Edit Agent

This commit is contained in:
ciregenz
2026-05-22 02:29:31 -07:00
parent 0fd5fb8653
commit 7715d26d4b
2 changed files with 91 additions and 11 deletions
@@ -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,
}
+16 -11
View File
@@ -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}",