Add JSON-based route registration system with API handler plugins

Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-01-10 23:04:18 +00:00
parent 147b045b0a
commit 2d302067b2
15 changed files with 347 additions and 1 deletions

View File

@@ -0,0 +1,13 @@
{
"name": "web_server_json_routes",
"version": "1.0.0",
"description": "Web server with routes defined in JSON workflow",
"main": "workflow.json",
"author": "AutoMetabuilder",
"metadata": {
"label": "Web Server (JSON Routes)",
"tags": ["web", "server", "json-routes"],
"icon": "web",
"category": "templates"
}
}

View File

@@ -0,0 +1,135 @@
{
"name": "Web Server with JSON Routes",
"active": true,
"nodes": [
{
"id": "configure_logging",
"name": "Configure Logging",
"type": "backend.configure_logging",
"typeVersion": 1,
"position": [0, 0],
"parameters": {}
},
{
"id": "load_env",
"name": "Load Environment",
"type": "backend.load_env",
"typeVersion": 1,
"position": [300, 0],
"parameters": {}
},
{
"id": "create_app",
"name": "Create Flask App",
"type": "web.create_flask_app",
"typeVersion": 1,
"position": [600, 0],
"parameters": {
"name": "autometabuilder",
"config": {
"JSON_SORT_KEYS": false
}
}
},
{
"id": "register_api_routes",
"name": "Register API Routes",
"type": "web.register_routes",
"typeVersion": 1,
"position": [900, 0],
"parameters": {
"blueprint_name": "api",
"routes": [
{
"path": "/api/navigation",
"methods": ["GET"],
"handler": "web.api_navigation",
"handler_type": "plugin"
},
{
"path": "/api/workflow/packages",
"methods": ["GET"],
"handler": "web.api_workflow_packages",
"handler_type": "plugin"
},
{
"path": "/api/workflow/plugins",
"methods": ["GET"],
"handler": "web.api_workflow_plugins",
"handler_type": "plugin"
},
{
"path": "/api/workflow/graph",
"methods": ["GET"],
"handler": "web.api_workflow_graph",
"handler_type": "plugin"
},
{
"path": "/api/translation-options",
"methods": ["GET"],
"handler": "web.api_translation_options",
"handler_type": "plugin"
}
]
}
},
{
"id": "start_server",
"name": "Start Web Server",
"type": "web.start_server",
"typeVersion": 1,
"position": [1200, 0],
"parameters": {
"host": "0.0.0.0",
"port": 8000,
"debug": false
}
}
],
"connections": {
"Configure Logging": {
"main": {
"0": [
{
"node": "Load Environment",
"type": "main",
"index": 0
}
]
}
},
"Load Environment": {
"main": {
"0": [
{
"node": "Create Flask App",
"type": "main",
"index": 0
}
]
}
},
"Create Flask App": {
"main": {
"0": [
{
"node": "Register API Routes",
"type": "main",
"index": 0
}
]
}
},
"Register API Routes": {
"main": {
"0": [
{
"node": "Start Web Server",
"type": "main",
"index": 0
}
]
}
}
}
}

View File

@@ -122,5 +122,11 @@
"web.update_translation": "autometabuilder.workflow.plugins.web.web_update_translation.web_update_translation.run",
"web.write_messages_dir": "autometabuilder.workflow.plugins.web.web_write_messages_dir.web_write_messages_dir.run",
"web.write_prompt": "autometabuilder.workflow.plugins.web.web_write_prompt.web_write_prompt.run",
"web.write_workflow": "autometabuilder.workflow.plugins.web.web_write_workflow.web_write_workflow.run"
"web.write_workflow": "autometabuilder.workflow.plugins.web.web_write_workflow.web_write_workflow.run",
"web.register_routes": "autometabuilder.workflow.plugins.web.web_register_routes.web_register_routes.run",
"web.api_navigation": "autometabuilder.workflow.plugins.web.web_api_navigation.web_api_navigation.run",
"web.api_workflow_packages": "autometabuilder.workflow.plugins.web.web_api_workflow_packages.web_api_workflow_packages.run",
"web.api_workflow_plugins": "autometabuilder.workflow.plugins.web.web_api_workflow_plugins.web_api_workflow_plugins.run",
"web.api_workflow_graph": "autometabuilder.workflow.plugins.web.web_api_workflow_graph.web_api_workflow_graph.run",
"web.api_translation_options": "autometabuilder.workflow.plugins.web.web_api_translation_options.web_api_translation_options.run"
}

View File

@@ -0,0 +1,8 @@
{
"name": "web.api_navigation",
"version": "1.0.0",
"description": "Handle /api/navigation endpoint",
"main": "web_api_navigation.py",
"author": "AutoMetabuilder",
"category": "web"
}

View File

@@ -0,0 +1,7 @@
"""Workflow plugin: handle /api/navigation endpoint."""
def run(_runtime, _inputs):
"""Return navigation items."""
from autometabuilder.data import get_navigation_items
return {"result": {"navigation": get_navigation_items()}}

View File

@@ -0,0 +1,8 @@
{
"name": "web.api_translation_options",
"version": "1.0.0",
"description": "Handle /api/translation-options endpoint",
"main": "web_api_translation_options.py",
"author": "AutoMetabuilder",
"category": "web"
}

View File

@@ -0,0 +1,8 @@
"""Workflow plugin: handle /api/translation-options endpoint."""
def run(_runtime, _inputs):
"""Return available translations."""
from autometabuilder.data import list_translations
translations = list_translations()
return {"result": {"translations": translations}}

View File

@@ -0,0 +1,8 @@
{
"name": "web.api_workflow_graph",
"version": "1.0.0",
"description": "Handle /api/workflow/graph endpoint",
"main": "web_api_workflow_graph.py",
"author": "AutoMetabuilder",
"category": "web"
}

View File

@@ -0,0 +1,8 @@
"""Workflow plugin: handle /api/workflow/graph endpoint."""
def run(_runtime, _inputs):
"""Return workflow graph."""
from autometabuilder.workflow.workflow_graph import build_workflow_graph
graph = build_workflow_graph()
return {"result": graph}

View File

@@ -0,0 +1,8 @@
{
"name": "web.api_workflow_packages",
"version": "1.0.0",
"description": "Handle /api/workflow/packages endpoint",
"main": "web_api_workflow_packages.py",
"author": "AutoMetabuilder",
"category": "web"
}

View File

@@ -0,0 +1,8 @@
"""Workflow plugin: handle /api/workflow/packages endpoint."""
def run(_runtime, _inputs):
"""Return workflow packages."""
from autometabuilder.data import load_workflow_packages, summarize_workflow_packages
packages = load_workflow_packages()
return {"result": {"packages": summarize_workflow_packages(packages)}}

View File

@@ -0,0 +1,8 @@
{
"name": "web.api_workflow_plugins",
"version": "1.0.0",
"description": "Handle /api/workflow/plugins endpoint",
"main": "web_api_workflow_plugins.py",
"author": "AutoMetabuilder",
"category": "web"
}

View File

@@ -0,0 +1,9 @@
"""Workflow plugin: handle /api/workflow/plugins endpoint."""
def run(_runtime, _inputs):
"""Return workflow plugins metadata."""
from autometabuilder.utils import load_metadata
metadata = load_metadata()
plugins = metadata.get("workflow_plugins", {})
return {"result": {"plugins": plugins}}

View File

@@ -0,0 +1,8 @@
{
"name": "web.register_routes",
"version": "1.0.0",
"description": "Register Flask routes from JSON configuration",
"main": "web_register_routes.py",
"author": "AutoMetabuilder",
"category": "web"
}

View File

@@ -0,0 +1,104 @@
"""Workflow plugin: register routes from JSON configuration."""
from flask import Blueprint, jsonify, request
def run(runtime, inputs):
"""
Register routes from JSON configuration.
This allows routes to be defined declaratively in the workflow JSON
rather than in Python code.
Inputs:
blueprint_name: Name for the blueprint (required)
routes: List of route configurations (required)
Each route should have:
- path: The URL path (e.g., "/api/navigation")
- methods: List of HTTP methods (default: ["GET"])
- handler: Name of the handler function or plugin to call
- handler_type: "plugin" or "function" (default: "plugin")
- handler_inputs: Inputs to pass to the plugin/function (optional)
Returns:
dict: Contains the blueprint in result
"""
app = runtime.context.get("flask_app")
if not app:
return {"error": "Flask app not found in context. Run web.create_flask_app first."}
blueprint_name = inputs.get("blueprint_name")
if not blueprint_name:
return {"error": "blueprint_name is required"}
routes = inputs.get("routes", [])
if not routes:
return {"error": "routes list is required"}
# Create blueprint
blueprint = Blueprint(blueprint_name, __name__)
# Register each route
for route_config in routes:
path = route_config.get("path")
if not path:
runtime.logger.error(f"Route missing 'path' in {blueprint_name}")
continue
methods = route_config.get("methods", ["GET"])
handler = route_config.get("handler")
handler_type = route_config.get("handler_type", "plugin")
handler_inputs = route_config.get("handler_inputs", {})
if not handler:
runtime.logger.error(f"Route {path} missing 'handler' in {blueprint_name}")
continue
# Create route handler function
def make_handler(handler_name, h_type, h_inputs):
"""Create a handler function with captured variables."""
def route_handler():
try:
if h_type == "plugin":
# Execute plugin and return result
from autometabuilder.workflow.plugin_registry import load_plugin_map, PluginRegistry
plugin_map = load_plugin_map()
registry = PluginRegistry(plugin_map)
plugin = registry.get(handler_name)
if not plugin:
return jsonify({"error": f"Plugin {handler_name} not found"}), 500
# Merge handler inputs with any request data
inputs_copy = dict(h_inputs)
if request.method == "POST" and request.is_json:
inputs_copy.update(request.get_json())
result = plugin(runtime, inputs_copy)
# If result has a "result" key, return that
if isinstance(result, dict) and "result" in result:
return jsonify(result["result"]), 200
return jsonify(result), 200
else:
# For function type, could load and call a function
return jsonify({"error": "Function handler type not yet implemented"}), 500
except Exception as e:
runtime.logger.error(f"Error in route handler {path}: {e}")
return jsonify({"error": str(e)}), 500
return route_handler
# Add route to blueprint
handler_func = make_handler(handler, handler_type, handler_inputs)
handler_func.__name__ = f"{blueprint_name}_{path.replace('/', '_')}"
blueprint.add_url_rule(path, view_func=handler_func, methods=methods)
# Register blueprint with app
app.register_blueprint(blueprint)
return {
"result": blueprint,
"message": f"Registered blueprint '{blueprint_name}' with {len(routes)} routes"
}