mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-28 07:44:56 +00:00
refactor(workflow): convert all plugins to class/struct + factory pattern
- Python: class extending NodeExecutor + factory.py (80+ plugins) - TypeScript: class implements NodeExecutor + factory.ts (7 groups, 116 classes) - Go: struct with methods + factory.go (36 plugins) - Rust: struct impl NodeExecutor trait + factory.rs (54 plugins) - Mojo: struct + factory.mojo (11 plugins) All package.json files now include: - files array listing source files - metadata.class/struct field - metadata.entrypoint field This enables a unified plugin loading system across all languages with no import side effects (Spring-style DI pattern). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
173
workflow/plugins/python/factory.py
Normal file
173
workflow/plugins/python/factory.py
Normal file
@@ -0,0 +1,173 @@
|
||||
"""
|
||||
Plugin factory for creating workflow plugins from simple functions.
|
||||
|
||||
This module provides a factory pattern for generating plugins. Plugins should
|
||||
NOT call these functions at module load time - instead they should just export
|
||||
NODE_TYPE, CATEGORY, DESCRIPTION, and impl. The registry handles instantiation.
|
||||
"""
|
||||
|
||||
from typing import Any, Callable, Dict, List
|
||||
|
||||
from .base import NodeExecutor
|
||||
|
||||
|
||||
def create_plugin(
|
||||
node_type: str,
|
||||
category: str,
|
||||
description: str,
|
||||
execute_fn: Callable[[Dict[str, Any], Any], Dict[str, Any]],
|
||||
) -> NodeExecutor:
|
||||
"""
|
||||
Create a plugin executor from a simple function.
|
||||
|
||||
Args:
|
||||
node_type: The node type identifier (e.g., "math.add")
|
||||
category: Plugin category (e.g., "math")
|
||||
description: Human-readable description
|
||||
execute_fn: Function that takes (inputs, runtime) and returns result dict
|
||||
|
||||
Returns:
|
||||
NodeExecutor instance with run() method exposed
|
||||
"""
|
||||
|
||||
class DynamicExecutor(NodeExecutor):
|
||||
pass
|
||||
|
||||
DynamicExecutor.node_type = node_type
|
||||
DynamicExecutor.category = category
|
||||
DynamicExecutor.description = description
|
||||
DynamicExecutor.execute = lambda self, inputs, runtime=None: execute_fn(
|
||||
inputs, runtime
|
||||
)
|
||||
|
||||
return DynamicExecutor()
|
||||
|
||||
|
||||
def wrap_math_impl(
|
||||
fn: Callable[..., float],
|
||||
input_keys: List[str] = None,
|
||||
array_key: str = None,
|
||||
) -> Callable[[Dict[str, Any], Any], Dict[str, Any]]:
|
||||
"""
|
||||
Wrap a math function to handle common input patterns.
|
||||
|
||||
Args:
|
||||
fn: Math function to apply
|
||||
input_keys: List of input parameter names (for binary ops like a, b)
|
||||
array_key: Key for array input (for reduce ops like sum)
|
||||
|
||||
Returns:
|
||||
Wrapped impl function
|
||||
"""
|
||||
|
||||
def impl(inputs, runtime=None):
|
||||
try:
|
||||
if array_key:
|
||||
values = inputs.get(array_key, inputs.get("values", []))
|
||||
result = fn([float(v) for v in values])
|
||||
elif input_keys:
|
||||
args = [float(inputs.get(k, 0)) for k in input_keys]
|
||||
result = fn(*args)
|
||||
else:
|
||||
value = float(inputs.get("value", 0))
|
||||
result = fn(value)
|
||||
return {"result": result}
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
return impl
|
||||
|
||||
|
||||
def wrap_string_impl(
|
||||
fn: Callable[[str, Dict[str, Any]], str],
|
||||
) -> Callable[[Dict[str, Any], Any], Dict[str, Any]]:
|
||||
"""
|
||||
Wrap a string function to handle common input patterns.
|
||||
|
||||
Args:
|
||||
fn: Function that takes (value, inputs) and returns transformed string
|
||||
|
||||
Returns:
|
||||
Wrapped impl function
|
||||
"""
|
||||
|
||||
def impl(inputs, runtime=None):
|
||||
try:
|
||||
value = str(inputs.get("value", inputs.get("text", "")))
|
||||
result = fn(value, inputs)
|
||||
return {"result": result}
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
return impl
|
||||
|
||||
|
||||
def wrap_logic_impl(
|
||||
fn: Callable[[Dict[str, Any]], bool],
|
||||
) -> Callable[[Dict[str, Any], Any], Dict[str, Any]]:
|
||||
"""
|
||||
Wrap a logic function to handle common input patterns.
|
||||
|
||||
Args:
|
||||
fn: Function that takes inputs and returns boolean
|
||||
|
||||
Returns:
|
||||
Wrapped impl function
|
||||
"""
|
||||
|
||||
def impl(inputs, runtime=None):
|
||||
try:
|
||||
result = fn(inputs)
|
||||
return {"result": result}
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
return impl
|
||||
|
||||
|
||||
def wrap_list_impl(
|
||||
fn: Callable[[List[Any], Dict[str, Any]], Any],
|
||||
) -> Callable[[Dict[str, Any], Any], Dict[str, Any]]:
|
||||
"""
|
||||
Wrap a list function to handle common input patterns.
|
||||
|
||||
Args:
|
||||
fn: Function that takes (array, inputs) and returns result
|
||||
|
||||
Returns:
|
||||
Wrapped impl function
|
||||
"""
|
||||
|
||||
def impl(inputs, runtime=None):
|
||||
try:
|
||||
array = inputs.get("array", inputs.get("list", []))
|
||||
result = fn(array, inputs)
|
||||
return {"result": result}
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
return impl
|
||||
|
||||
|
||||
def wrap_dict_impl(
|
||||
fn: Callable[[Dict[str, Any], Dict[str, Any]], Any],
|
||||
) -> Callable[[Dict[str, Any], Any], Dict[str, Any]]:
|
||||
"""
|
||||
Wrap a dict function to handle common input patterns.
|
||||
|
||||
Args:
|
||||
fn: Function that takes (obj, inputs) and returns result
|
||||
|
||||
Returns:
|
||||
Wrapped impl function
|
||||
"""
|
||||
|
||||
def impl(inputs, runtime=None):
|
||||
try:
|
||||
obj = inputs.get("object", inputs.get("dict", {}))
|
||||
result = fn(obj, inputs)
|
||||
return {"result": result}
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
return impl
|
||||
Reference in New Issue
Block a user