diff --git a/server.py b/server.py index a8b64f4..b8b91b9 100644 --- a/server.py +++ b/server.py @@ -1324,10 +1324,43 @@ async def run_plan_visualization(run_id: str, request: Request): except (json.JSONDecodeError, IOError): continue + # If no cached plan, try to generate one from the recipe + if not plan_data: + recipe_name = run.recipe.replace("recipe:", "") if run.recipe.startswith("recipe:") else run.recipe + recipe_status = None + for recipe in list_all_recipes(): + if recipe.name == recipe_name: + recipe_status = recipe + break + + if recipe_status: + recipe_path = cache_manager.get_by_content_hash(recipe_status.recipe_id) + if recipe_path and recipe_path.exists(): + try: + recipe_yaml = recipe_path.read_text() + # Build input_hashes mapping from run inputs + input_hashes = {} + for i, var_input in enumerate(recipe_status.variable_inputs): + if i < len(run.inputs): + input_hashes[var_input.node_id] = run.inputs[i] + + # Try to generate plan using the orchestrate module + try: + from tasks.orchestrate import generate_plan as gen_plan_task + # Call synchronously (it's fast for just planning) + plan_result = gen_plan_task(recipe_yaml, input_hashes) + if plan_result and plan_result.get("status") == "planned": + plan_data = plan_result + except ImportError: + pass + except Exception as e: + logger.warning(f"Failed to generate plan for run {run_id}: {e}") + # Build sub-navigation tabs tabs_html = render_run_sub_tabs(run_id, active="plan") if not plan_data: + # Show a simpler visualization based on the run's recipe structure content = f''' @@ -1340,8 +1373,8 @@ async def run_plan_visualization(run_id: str, request: Request):

Execution Plan

-

No execution plan available for this run.

-

Plans are generated when using recipe-based runs with the v2 API.

+

Could not generate execution plan for this run.

+

This may be a legacy effect-based run without a recipe, or the recipe is no longer available.

''' return HTMLResponse(render_page_with_cytoscape(f"Plan: {run_id[:16]}...", content, ctx.actor_id, active_tab="runs"))