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:
2026-01-22 14:53:04 +00:00
parent 2562c2f55b
commit 7ce8b4ae8a
653 changed files with 13243 additions and 3034 deletions

View File

@@ -1,6 +1,9 @@
"""Workflow plugin: AI request."""
from tenacity import retry, stop_after_attempt, wait_exponential
from ...base import NodeExecutor
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10))
def _get_completion(client, model, messages, tools):
@@ -15,25 +18,32 @@ def _get_completion(client, model, messages, tools):
)
def run(runtime, inputs):
"""Invoke the model with current messages."""
messages = list(inputs.get("messages") or [])
response = _get_completion(
runtime.context["client"],
runtime.context["model_name"],
messages,
runtime.context["tools"]
)
resp_msg = response.choices[0].message
runtime.logger.info(
resp_msg.content
if resp_msg.content
else runtime.context["msgs"]["info_tool_call_requested"]
)
messages.append(resp_msg)
tool_calls = getattr(resp_msg, "tool_calls", None) or []
return {
"response": resp_msg,
"has_tool_calls": bool(tool_calls),
"tool_calls_count": len(tool_calls)
}
class CoreAiRequest(NodeExecutor):
"""Invoke the AI model with current messages."""
node_type = "core.ai_request"
category = "core"
description = "Invoke the AI model with current messages and return the response"
def execute(self, inputs, runtime=None):
"""Invoke the model with current messages."""
messages = list(inputs.get("messages") or [])
response = _get_completion(
runtime.context["client"],
runtime.context["model_name"],
messages,
runtime.context["tools"]
)
resp_msg = response.choices[0].message
runtime.logger.info(
resp_msg.content
if resp_msg.content
else runtime.context["msgs"]["info_tool_call_requested"]
)
messages.append(resp_msg)
tool_calls = getattr(resp_msg, "tool_calls", None) or []
return {
"response": resp_msg,
"has_tool_calls": bool(tool_calls),
"tool_calls_count": len(tool_calls)
}

View File

@@ -0,0 +1,8 @@
"""Factory for CoreAiRequest plugin."""
from .core_ai_request import CoreAiRequest
def create():
"""Create a new CoreAiRequest instance."""
return CoreAiRequest()

View File

@@ -1,13 +1,16 @@
{
"name": "@metabuilder/core_ai_request",
"version": "1.0.0",
"description": "core_ai_request plugin",
"description": "Invoke the AI model with current messages and return the response",
"author": "MetaBuilder",
"license": "MIT",
"keywords": ["core", "workflow", "plugin"],
"main": "core_ai_request.py",
"files": ["core_ai_request.py", "factory.py"],
"metadata": {
"plugin_type": "core.ai_request",
"category": "core"
"category": "core",
"class": "CoreAiRequest",
"entrypoint": "execute"
}
}

View File

@@ -1,13 +1,22 @@
"""Workflow plugin: append context message."""
from ...base import NodeExecutor
def run(runtime, inputs):
class CoreAppendContextMessage(NodeExecutor):
"""Append context to the message list."""
messages = list(inputs.get("messages") or [])
context_val = inputs.get("context")
if context_val:
messages.append({
"role": "system",
"content": f"{runtime.context['msgs']['sdlc_context_label']}{context_val}",
})
return {"messages": messages}
node_type = "core.append_context_message"
category = "core"
description = "Append context information to the message list as a system message"
def execute(self, inputs, runtime=None):
"""Append context to the message list."""
messages = list(inputs.get("messages") or [])
context_val = inputs.get("context")
if context_val:
messages.append({
"role": "system",
"content": f"{runtime.context['msgs']['sdlc_context_label']}{context_val}",
})
return {"messages": messages}

View File

@@ -0,0 +1,8 @@
"""Factory for CoreAppendContextMessage plugin."""
from .core_append_context_message import CoreAppendContextMessage
def create():
"""Create a new CoreAppendContextMessage instance."""
return CoreAppendContextMessage()

View File

@@ -1,13 +1,16 @@
{
"name": "@metabuilder/core_append_context_message",
"version": "1.0.0",
"description": "core_append_context_message plugin",
"description": "Append context information to the message list as a system message",
"author": "MetaBuilder",
"license": "MIT",
"keywords": ["core", "workflow", "plugin"],
"main": "core_append_context_message.py",
"files": ["core_append_context_message.py", "factory.py"],
"metadata": {
"plugin_type": "core.append_context_message",
"category": "core"
"category": "core",
"class": "CoreAppendContextMessage",
"entrypoint": "execute"
}
}

View File

@@ -1,7 +1,10 @@
"""Workflow plugin: append tool results."""
import os
import re
from ...base import NodeExecutor
def _is_mvp_reached() -> bool:
"""Check if the MVP section in ROADMAP.md is completed."""
@@ -31,14 +34,21 @@ def _is_mvp_reached() -> bool:
return False
def run(runtime, inputs):
class CoreAppendToolResults(NodeExecutor):
"""Append tool results to the message list."""
messages = list(inputs.get("messages") or [])
tool_results = inputs.get("tool_results") or []
if tool_results:
messages.extend(tool_results)
if runtime.context.get("args", {}).get("yolo") and _is_mvp_reached():
runtime.logger.info("MVP reached. Stopping YOLO loop.")
node_type = "core.append_tool_results"
category = "core"
description = "Append tool execution results to the message list"
return {"messages": messages}
def execute(self, inputs, runtime=None):
"""Append tool results to the message list."""
messages = list(inputs.get("messages") or [])
tool_results = inputs.get("tool_results") or []
if tool_results:
messages.extend(tool_results)
if runtime.context.get("args", {}).get("yolo") and _is_mvp_reached():
runtime.logger.info("MVP reached. Stopping YOLO loop.")
return {"messages": messages}

View File

@@ -0,0 +1,8 @@
"""Factory for CoreAppendToolResults plugin."""
from .core_append_tool_results import CoreAppendToolResults
def create():
"""Create a new CoreAppendToolResults instance."""
return CoreAppendToolResults()

View File

@@ -1,13 +1,16 @@
{
"name": "@metabuilder/core_append_tool_results",
"version": "1.0.0",
"description": "core_append_tool_results plugin",
"description": "Append tool execution results to the message list",
"author": "MetaBuilder",
"license": "MIT",
"keywords": ["core", "workflow", "plugin"],
"main": "core_append_tool_results.py",
"files": ["core_append_tool_results.py", "factory.py"],
"metadata": {
"plugin_type": "core.append_tool_results",
"category": "core"
"category": "core",
"class": "CoreAppendToolResults",
"entrypoint": "execute"
}
}

View File

@@ -1,8 +1,17 @@
"""Workflow plugin: append user instruction."""
from ...base import NodeExecutor
def run(runtime, inputs):
"""Append the next user instruction."""
messages = list(inputs.get("messages") or [])
messages.append({"role": "user", "content": runtime.context["msgs"]["user_next_step"]})
return {"messages": messages}
class CoreAppendUserInstruction(NodeExecutor):
"""Append the next user instruction to the message list."""
node_type = "core.append_user_instruction"
category = "core"
description = "Append the next user instruction to the message list"
def execute(self, inputs, runtime=None):
"""Append the next user instruction."""
messages = list(inputs.get("messages") or [])
messages.append({"role": "user", "content": runtime.context["msgs"]["user_next_step"]})
return {"messages": messages}

View File

@@ -0,0 +1,8 @@
"""Factory for CoreAppendUserInstruction plugin."""
from .core_append_user_instruction import CoreAppendUserInstruction
def create():
"""Create a new CoreAppendUserInstruction instance."""
return CoreAppendUserInstruction()

View File

@@ -1,13 +1,16 @@
{
"name": "@metabuilder/core_append_user_instruction",
"version": "1.0.0",
"description": "core_append_user_instruction plugin",
"description": "Append the next user instruction to the message list",
"author": "MetaBuilder",
"license": "MIT",
"keywords": ["core", "workflow", "plugin"],
"main": "core_append_user_instruction.py",
"files": ["core_append_user_instruction.py", "factory.py"],
"metadata": {
"plugin_type": "core.append_user_instruction",
"category": "core"
"category": "core",
"class": "CoreAppendUserInstruction",
"entrypoint": "execute"
}
}

View File

@@ -1,43 +1,53 @@
"""Workflow plugin: load SDLC context."""
import os
import logging
from ...base import NodeExecutor
logger = logging.getLogger("metabuilder")
def run(runtime, _inputs):
class CoreLoadContext(NodeExecutor):
"""Load SDLC context into the workflow store."""
gh = runtime.context.get("gh")
msgs = runtime.context.get("msgs", {})
sdlc_context = ""
node_type = "core.load_context"
category = "core"
description = "Load SDLC context from ROADMAP.md and GitHub issues/PRs"
# Load ROADMAP.md if it exists
if os.path.exists("ROADMAP.md"):
with open("ROADMAP.md", "r", encoding="utf-8") as f:
roadmap_content = f.read()
label = msgs.get("roadmap_label", "ROADMAP.md Content:")
sdlc_context += f"\n{label}\n{roadmap_content}\n"
else:
msg = msgs.get(
"missing_roadmap_msg",
"ROADMAP.md is missing. Please analyze the repository and create it."
)
sdlc_context += f"\n{msg}\n"
def execute(self, inputs, runtime=None):
"""Load SDLC context into the workflow store."""
gh = runtime.context.get("gh")
msgs = runtime.context.get("msgs", {})
# Load GitHub issues and PRs if integration is available
if gh:
try:
issues = gh.get_open_issues()
issue_list = "\n".join([f"- #{i.number}: {i.title}" for i in issues[:5]])
if issue_list:
sdlc_context += f"\n{msgs['open_issues_label']}\n{issue_list}"
sdlc_context = ""
prs = gh.get_pull_requests()
pr_list = "\n".join([f"- #{p.number}: {p.title}" for p in prs[:5]])
if pr_list:
sdlc_context += f"\n{msgs['open_prs_label']}\n{pr_list}"
except Exception as error:
logger.error(msgs.get("error_sdlc_context", "Error: {error}").format(error=error))
# Load ROADMAP.md if it exists
if os.path.exists("ROADMAP.md"):
with open("ROADMAP.md", "r", encoding="utf-8") as f:
roadmap_content = f.read()
label = msgs.get("roadmap_label", "ROADMAP.md Content:")
sdlc_context += f"\n{label}\n{roadmap_content}\n"
else:
msg = msgs.get(
"missing_roadmap_msg",
"ROADMAP.md is missing. Please analyze the repository and create it."
)
sdlc_context += f"\n{msg}\n"
return {"context": sdlc_context}
# Load GitHub issues and PRs if integration is available
if gh:
try:
issues = gh.get_open_issues()
issue_list = "\n".join([f"- #{i.number}: {i.title}" for i in issues[:5]])
if issue_list:
sdlc_context += f"\n{msgs['open_issues_label']}\n{issue_list}"
prs = gh.get_pull_requests()
pr_list = "\n".join([f"- #{p.number}: {p.title}" for p in prs[:5]])
if pr_list:
sdlc_context += f"\n{msgs['open_prs_label']}\n{pr_list}"
except Exception as error:
logger.error(msgs.get("error_sdlc_context", "Error: {error}").format(error=error))
return {"context": sdlc_context}

View File

@@ -0,0 +1,8 @@
"""Factory for CoreLoadContext plugin."""
from .core_load_context import CoreLoadContext
def create():
"""Create a new CoreLoadContext instance."""
return CoreLoadContext()

View File

@@ -1,13 +1,16 @@
{
"name": "@metabuilder/core_load_context",
"version": "1.0.0",
"description": "core_load_context plugin",
"description": "Load SDLC context from ROADMAP.md and GitHub issues/PRs",
"author": "MetaBuilder",
"license": "MIT",
"keywords": ["core", "workflow", "plugin"],
"main": "core_load_context.py",
"files": ["core_load_context.py", "factory.py"],
"metadata": {
"plugin_type": "core.load_context",
"category": "core"
"category": "core",
"class": "CoreLoadContext",
"entrypoint": "execute"
}
}

View File

@@ -1,37 +1,47 @@
"""Workflow plugin: run tool calls."""
import json
def run(runtime, inputs):
from ...base import NodeExecutor
class CoreRunToolCalls(NodeExecutor):
"""Execute tool calls from an AI response."""
resp_msg = inputs.get("response")
tool_calls = getattr(resp_msg, "tool_calls", None) or []
if not resp_msg:
return {"tool_results": [], "no_tool_calls": True}
# Handle tool calls using tool map from context
tool_results = []
tool_map = runtime.context.get("tool_map", {})
node_type = "core.run_tool_calls"
category = "core"
description = "Execute tool calls from an AI response and return results"
for tool_call in tool_calls:
func_name = tool_call.function.name
if func_name in tool_map:
try:
import json
args = json.loads(tool_call.function.arguments)
result = tool_map[func_name](**args)
tool_results.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": str(result)
})
except Exception as e:
tool_results.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": f"Error: {str(e)}"
})
def execute(self, inputs, runtime=None):
"""Execute tool calls from an AI response."""
resp_msg = inputs.get("response")
tool_calls = getattr(resp_msg, "tool_calls", None) or []
if not resp_msg:
return {"tool_results": [], "no_tool_calls": True}
return {
"tool_results": tool_results,
"no_tool_calls": not bool(tool_calls)
}
# Handle tool calls using tool map from context
tool_results = []
tool_map = runtime.context.get("tool_map", {})
for tool_call in tool_calls:
func_name = tool_call.function.name
if func_name in tool_map:
try:
args = json.loads(tool_call.function.arguments)
result = tool_map[func_name](**args)
tool_results.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": str(result)
})
except Exception as e:
tool_results.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": f"Error: {str(e)}"
})
return {
"tool_results": tool_results,
"no_tool_calls": not bool(tool_calls)
}

View File

@@ -0,0 +1,8 @@
"""Factory for CoreRunToolCalls plugin."""
from .core_run_tool_calls import CoreRunToolCalls
def create():
"""Create a new CoreRunToolCalls instance."""
return CoreRunToolCalls()

View File

@@ -1,13 +1,16 @@
{
"name": "@metabuilder/core_run_tool_calls",
"version": "1.0.0",
"description": "core_run_tool_calls plugin",
"description": "Execute tool calls from an AI response and return results",
"author": "MetaBuilder",
"license": "MIT",
"keywords": ["core", "workflow", "plugin"],
"main": "core_run_tool_calls.py",
"files": ["core_run_tool_calls.py", "factory.py"],
"metadata": {
"plugin_type": "core.run_tool_calls",
"category": "core"
"category": "core",
"class": "CoreRunToolCalls",
"entrypoint": "execute"
}
}

View File

@@ -1,7 +1,16 @@
"""Workflow plugin: seed messages."""
from ...base import NodeExecutor
def run(runtime, _inputs):
class CoreSeedMessages(NodeExecutor):
"""Seed messages from the prompt."""
prompt = runtime.context["prompt"]
return {"messages": list(prompt["messages"])}
node_type = "core.seed_messages"
category = "core"
description = "Initialize the message list from the prompt configuration"
def execute(self, inputs, runtime=None):
"""Seed messages from the prompt."""
prompt = runtime.context["prompt"]
return {"messages": list(prompt["messages"])}

View File

@@ -0,0 +1,8 @@
"""Factory for CoreSeedMessages plugin."""
from .core_seed_messages import CoreSeedMessages
def create():
"""Create a new CoreSeedMessages instance."""
return CoreSeedMessages()

View File

@@ -1,13 +1,16 @@
{
"name": "@metabuilder/core_seed_messages",
"version": "1.0.0",
"description": "core_seed_messages plugin",
"description": "Initialize the message list from the prompt configuration",
"author": "MetaBuilder",
"license": "MIT",
"keywords": ["core", "workflow", "plugin"],
"main": "core_seed_messages.py",
"files": ["core_seed_messages.py", "factory.py"],
"metadata": {
"plugin_type": "core.seed_messages",
"category": "core"
"category": "core",
"class": "CoreSeedMessages",
"entrypoint": "execute"
}
}