Replace plan JSON with colored S-expression display
- Add plan_to_sexp() to convert plan to S-expression format - Syntax highlighting for S-expressions: - Pink: special forms (plan, recipe, def, ->) - Blue: primitives (source, effect, sequence, etc.) - Purple: keywords (:input, :name, etc.) - Green: strings - Yellow: parentheses - Gray: comments Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,59 @@ from ..services.run_service import RunService
|
||||
router = APIRouter()
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def plan_to_sexp(plan: dict, recipe_name: str = None) -> str:
|
||||
"""Convert a plan to S-expression format for display."""
|
||||
if not plan or not plan.get("steps"):
|
||||
return ";; No plan available"
|
||||
|
||||
lines = []
|
||||
lines.append(f'(plan "{recipe_name or "unknown"}"')
|
||||
|
||||
# Group nodes by type for cleaner output
|
||||
steps = plan.get("steps", [])
|
||||
|
||||
for step in steps:
|
||||
step_id = step.get("id", "?")
|
||||
step_type = step.get("type", "EFFECT")
|
||||
inputs = step.get("inputs", [])
|
||||
config = step.get("config", {})
|
||||
|
||||
# Build the step S-expression
|
||||
if step_type == "SOURCE":
|
||||
if config.get("input"):
|
||||
# Variable input
|
||||
input_name = config.get("name", config.get("input", "input"))
|
||||
lines.append(f' (source :input "{input_name}")')
|
||||
elif config.get("asset"):
|
||||
# Fixed asset
|
||||
lines.append(f' (source {config.get("asset", step_id)})')
|
||||
else:
|
||||
lines.append(f' (source {step_id})')
|
||||
elif step_type == "EFFECT":
|
||||
effect_name = config.get("effect", step_id)
|
||||
if inputs:
|
||||
inp_str = " ".join(inputs)
|
||||
lines.append(f' (-> {inp_str} (effect {effect_name}))')
|
||||
else:
|
||||
lines.append(f' (effect {effect_name})')
|
||||
elif step_type == "SEQUENCE":
|
||||
if inputs:
|
||||
inp_str = " ".join(inputs)
|
||||
lines.append(f' (sequence {inp_str})')
|
||||
else:
|
||||
lines.append(f' (sequence)')
|
||||
else:
|
||||
# Generic node
|
||||
if inputs:
|
||||
inp_str = " ".join(inputs)
|
||||
lines.append(f' ({step_type.lower()} {inp_str})')
|
||||
else:
|
||||
lines.append(f' ({step_type.lower()} {step_id})')
|
||||
|
||||
lines.append(')')
|
||||
return "\n".join(lines)
|
||||
|
||||
RUNS_KEY_PREFIX = "artdag:run:"
|
||||
|
||||
|
||||
@@ -258,6 +311,9 @@ async def get_run(
|
||||
}
|
||||
})
|
||||
|
||||
# Generate S-expression representation of the plan
|
||||
plan_sexp = plan_to_sexp(plan, run.get("recipe_name"))
|
||||
|
||||
templates = get_templates(request)
|
||||
return render(templates, "runs/detail.html", request,
|
||||
run=run,
|
||||
@@ -266,6 +322,7 @@ async def get_run(
|
||||
run_inputs=run_inputs,
|
||||
dag_elements=dag_elements,
|
||||
output_media_type=output_media_type,
|
||||
plan_sexp=plan_sexp,
|
||||
active_tab="runs",
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user