mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 22:04:56 +00:00
feat: Add Python plugins from AutoMetabuilder + restructure workflow folder
Restructure workflow/ for multi-language plugin support:
- Rename src/ to core/ (engine code: DAG executor, registry, types)
- Create executor/{cpp,python,ts}/ for language-specific runtimes
- Consolidate plugins to plugins/{ts,python}/ by language then category
Add 80+ Python plugins from AutoMetabuilder in 14 categories:
- control: bot control, switch logic, state management
- convert: type conversions (json, boolean, dict, list, number, string)
- core: AI requests, context management, tool calls
- dict: dictionary operations (get, set, keys, values, merge)
- list: list operations (concat, find, sort, slice, filter)
- logic: boolean logic (and, or, xor, equals, comparisons)
- math: arithmetic operations (add, subtract, multiply, power, etc.)
- string: string manipulation (concat, split, replace, format)
- notifications: Slack, Discord integrations
- test: assertion helpers and test suite runner
- tools: file operations, git, docker, testing utilities
- utils: filtering, mapping, reducing, condition branching
- var: variable store operations (get, set, delete, exists)
- web: Flask server, environment variables, JSON handling
Add language executor runtimes:
- TypeScript: direct import execution (default, fast startup)
- Python: child process with JSON stdin/stdout communication
- C++: placeholder for native FFI bindings (Phase 3)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
44
workflow/plugins/python/web/__init__.py
Normal file
44
workflow/plugins/python/web/__init__.py
Normal file
@@ -0,0 +1,44 @@
|
||||
"""Web workflow plugins: Flask server, API endpoints, file I/O, translations.
|
||||
|
||||
These plugins provide workflow-based access to web data operations, enabling
|
||||
declarative workflows to interact with web-related functionality.
|
||||
|
||||
Available Plugins:
|
||||
|
||||
Environment Management:
|
||||
- web_get_env_vars - Load environment variables
|
||||
- web_persist_env_vars - Save environment variables
|
||||
|
||||
File I/O:
|
||||
- web_read_json - Read JSON files
|
||||
- web_get_recent_logs - Get recent log entries
|
||||
- web_load_messages - Load translation messages
|
||||
|
||||
Translation Management:
|
||||
- web_list_translations - List available translations
|
||||
- web_load_translation - Load a translation
|
||||
- web_create_translation - Create new translation
|
||||
- web_update_translation - Update translation
|
||||
- web_delete_translation - Delete translation
|
||||
- web_get_ui_messages - Get UI messages with fallback
|
||||
|
||||
Navigation & Metadata:
|
||||
- web_get_navigation_items - Get navigation menu items
|
||||
|
||||
Prompt Management:
|
||||
- web_get_prompt_content - Read prompt content
|
||||
- web_write_prompt - Write prompt content
|
||||
- web_build_prompt_yaml - Build YAML prompt
|
||||
|
||||
Workflow Operations:
|
||||
- web_get_workflow_content - Read workflow JSON
|
||||
- web_write_workflow - Write workflow JSON
|
||||
- web_load_workflow_packages - Load workflow packages
|
||||
- web_summarize_workflow_packages - Summarize packages
|
||||
|
||||
Flask Server Setup:
|
||||
- web_create_flask_app - Create Flask application
|
||||
- web_register_blueprint - Register Flask blueprints
|
||||
- web_start_server - Start Flask server
|
||||
- web_build_context - Build API context
|
||||
"""
|
||||
29
workflow/plugins/python/web/web_build_prompt_yaml.py
Normal file
29
workflow/plugins/python/web/web_build_prompt_yaml.py
Normal file
@@ -0,0 +1,29 @@
|
||||
"""Workflow plugin: build prompt YAML."""
|
||||
|
||||
|
||||
def run(_runtime, inputs):
|
||||
"""Build prompt YAML from system and user content."""
|
||||
system_content = inputs.get("system_content")
|
||||
user_content = inputs.get("user_content")
|
||||
model = inputs.get("model")
|
||||
|
||||
def indent_block(text):
|
||||
if not text:
|
||||
return ""
|
||||
return "\n ".join(line.rstrip() for line in text.splitlines())
|
||||
|
||||
model_value = model or "openai/gpt-4o"
|
||||
system_block = indent_block(system_content)
|
||||
user_block = indent_block(user_content)
|
||||
|
||||
yaml_content = f"""messages:
|
||||
- role: system
|
||||
content: >-
|
||||
{system_block}
|
||||
- role: user
|
||||
content: >-
|
||||
{user_block}
|
||||
model: {model_value}
|
||||
"""
|
||||
|
||||
return {"result": yaml_content}
|
||||
27
workflow/plugins/python/web/web_create_flask_app.py
Normal file
27
workflow/plugins/python/web/web_create_flask_app.py
Normal file
@@ -0,0 +1,27 @@
|
||||
"""Workflow plugin: create Flask app."""
|
||||
from flask import Flask
|
||||
|
||||
|
||||
def run(runtime, inputs):
|
||||
"""Create a Flask application instance.
|
||||
|
||||
Inputs:
|
||||
name: Application name (default: __name__)
|
||||
config: Dictionary of Flask configuration options
|
||||
|
||||
Returns:
|
||||
dict: Contains the Flask app in result
|
||||
"""
|
||||
name = inputs.get("name", "__main__")
|
||||
config = inputs.get("config", {})
|
||||
|
||||
app = Flask(name)
|
||||
|
||||
# Apply configuration
|
||||
for key, value in config.items():
|
||||
app.config[key] = value
|
||||
|
||||
# Store app in runtime context for other plugins to use
|
||||
runtime.context["flask_app"] = app
|
||||
|
||||
return {"result": app, "message": "Flask app created"}
|
||||
22
workflow/plugins/python/web/web_get_env_vars.py
Normal file
22
workflow/plugins/python/web/web_get_env_vars.py
Normal file
@@ -0,0 +1,22 @@
|
||||
"""Workflow plugin: get environment variables."""
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def run(_runtime, _inputs):
|
||||
"""Get environment variables from .env file."""
|
||||
env_path = Path(".env")
|
||||
if not env_path.exists():
|
||||
return {"result": {}}
|
||||
|
||||
result = {}
|
||||
for raw in env_path.read_text(encoding="utf-8").splitlines():
|
||||
line = raw.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
if "=" not in line:
|
||||
continue
|
||||
key, value = line.split("=", 1)
|
||||
value = value.strip().strip("'\"")
|
||||
result[key.strip()] = value
|
||||
|
||||
return {"result": result}
|
||||
12
workflow/plugins/python/web/web_get_prompt_content.py
Normal file
12
workflow/plugins/python/web/web_get_prompt_content.py
Normal file
@@ -0,0 +1,12 @@
|
||||
"""Workflow plugin: get prompt content."""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def run(_runtime, _inputs):
|
||||
"""Get prompt content from prompt file."""
|
||||
path = Path(os.environ.get("PROMPT_PATH", "prompt.yml"))
|
||||
if path.is_file():
|
||||
content = path.read_text(encoding="utf-8")
|
||||
return {"result": content}
|
||||
return {"result": ""}
|
||||
16
workflow/plugins/python/web/web_get_recent_logs.py
Normal file
16
workflow/plugins/python/web/web_get_recent_logs.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""Workflow plugin: get recent logs."""
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def run(_runtime, inputs):
|
||||
"""Get recent log entries."""
|
||||
lines = inputs.get("lines", 50)
|
||||
log_file = Path("metabuilder.log")
|
||||
|
||||
if not log_file.exists():
|
||||
return {"result": ""}
|
||||
|
||||
with log_file.open("r", encoding="utf-8") as handle:
|
||||
content = handle.readlines()
|
||||
|
||||
return {"result": "".join(content[-lines:])}
|
||||
15
workflow/plugins/python/web/web_persist_env_vars.py
Normal file
15
workflow/plugins/python/web/web_persist_env_vars.py
Normal file
@@ -0,0 +1,15 @@
|
||||
"""Workflow plugin: persist environment variables."""
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def run(_runtime, inputs):
|
||||
"""Persist environment variables to .env file."""
|
||||
from dotenv import set_key
|
||||
|
||||
updates = inputs.get("updates", {})
|
||||
env_path = Path(".env")
|
||||
env_path.touch(exist_ok=True)
|
||||
for key, value in updates.items():
|
||||
set_key(env_path, key, value)
|
||||
|
||||
return {"result": "Environment variables persisted"}
|
||||
21
workflow/plugins/python/web/web_read_json.py
Normal file
21
workflow/plugins/python/web/web_read_json.py
Normal file
@@ -0,0 +1,21 @@
|
||||
"""Workflow plugin: read JSON file."""
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def run(_runtime, inputs):
|
||||
"""Read JSON file."""
|
||||
path = inputs.get("path")
|
||||
if not path:
|
||||
return {"error": "path is required"}
|
||||
|
||||
path_obj = Path(path)
|
||||
if not path_obj.exists():
|
||||
return {"result": {}}
|
||||
|
||||
try:
|
||||
json_data = json.loads(path_obj.read_text(encoding="utf-8"))
|
||||
except json.JSONDecodeError:
|
||||
return {"result": {}}
|
||||
|
||||
return {"result": json_data}
|
||||
26
workflow/plugins/python/web/web_start_server.py
Normal file
26
workflow/plugins/python/web/web_start_server.py
Normal file
@@ -0,0 +1,26 @@
|
||||
"""Workflow plugin: start Flask server."""
|
||||
|
||||
|
||||
def run(runtime, inputs):
|
||||
"""Start the Flask web server.
|
||||
|
||||
Inputs:
|
||||
host: Host address (default: 0.0.0.0)
|
||||
port: Port number (default: 8000)
|
||||
debug: Enable debug mode (default: False)
|
||||
|
||||
Returns:
|
||||
dict: Success indicator (note: this blocks until server stops)
|
||||
"""
|
||||
app = runtime.context.get("flask_app")
|
||||
if not app:
|
||||
return {"error": "Flask app not found in context. Run web.create_flask_app first."}
|
||||
|
||||
host = inputs.get("host", "0.0.0.0")
|
||||
port = inputs.get("port", 8000)
|
||||
debug = inputs.get("debug", False)
|
||||
|
||||
# This will block until the server is stopped
|
||||
app.run(host=host, port=port, debug=debug)
|
||||
|
||||
return {"result": "Server stopped"}
|
||||
11
workflow/plugins/python/web/web_write_prompt.py
Normal file
11
workflow/plugins/python/web/web_write_prompt.py
Normal file
@@ -0,0 +1,11 @@
|
||||
"""Workflow plugin: write prompt."""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def run(_runtime, inputs):
|
||||
"""Write prompt content to file."""
|
||||
content = inputs.get("content", "")
|
||||
path = Path(os.environ.get("PROMPT_PATH", "prompt.yml"))
|
||||
path.write_text(content or "", encoding="utf-8")
|
||||
return {"result": "Prompt written successfully"}
|
||||
Reference in New Issue
Block a user