from fastapi import APIRouter, HTTPException from pytrace.core.registry import NodeRegistry from pytrace.core.executor import WorkflowExecutor from pytrace.model.graph import WorkflowGraph, Node, Edge from ..models.graph import GraphExecuteRequest router = APIRouter() @router.get("/plugins") async def get_plugins(): """ Gets the list of all available (registered) nodes and their specifications. This is used by the frontend to populate the node palette. """ specs = NodeRegistry.get_all_specs() # The old protocol expects a dictionary keyed by node type string. plugins = { spec.type: { "display_name": spec.name, "category": spec.category, "description": spec.description, "node_type": spec.node_type.value, "class_name": spec.type, # Using the unique type string as class_name "inputs": [p.dict() for p in spec.inputs], "outputs": [p.dict() for p in spec.outputs], "param_schema": [p.dict() for p in spec.params], } for spec in specs } return { "plugins": plugins, "total": len(plugins), "categories": NodeRegistry.get_categories() } @router.post("/execute") async def execute_graph(request: GraphExecuteRequest): """ Executes a workflow graph. """ try: # 1. Build the WorkflowGraph from the request graph = WorkflowGraph(name="Execution Graph") for node_data in request.nodes: graph.add_node(Node( id=node_data.id, type=node_data.type, name=node_data.name, params=node_data.params )) for edge_data in request.edges: graph.add_edge(Edge( source_node=edge_data.source_node, source_port=edge_data.source_port, target_node=edge_data.target_node, target_port=edge_data.target_port )) # 2. Instantiate the executor and run the graph executor = WorkflowExecutor() results = executor.execute(graph, initial_inputs=request.initial_inputs) # 3. Return the results return { "success": True, "results": results } except Exception as e: import traceback raise HTTPException( status_code=500, detail={ "error": str(e), "type": type(e).__name__, "traceback": traceback.format_exc() } )