molecule-ai-workspace-templ.../adapter.py
Hongming Wang 076ac2b67e fix: add Adapter alias + qualify bare runtime imports
Two compounding bugs from the post-#87 extraction caught by today's
template sweep (matches the same fixes already shipped in claude-code
and gemini-cli):

1. adapter.py never aliased LangGraphAdapter to the contract name
   `Adapter`, which `molecule_runtime.adapters.get_adapter()` reads
   via `getattr(mod, "Adapter")`. Without it, every workspace
   startup fails preflight with "no \`Adapter\` class is exported".

2. Two bare imports of runtime modules
   (`from agent`, `from a2a_executor`) never got qualified to
   `from molecule_runtime.X import Y`. They worked when runtime was
   bundled into workspace/ but explode in the standalone template
   repo with ModuleNotFoundError.

Same migration debt class fixed for hermes (a2a-sdk migration),
claude-code (5 imports), gemini-cli (4 imports + alias) earlier today.
Both gates now in molecule-ci PR #8 will catch this class of bug
at PR time going forward.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 05:51:29 -07:00

54 lines
1.8 KiB
Python

"""LangGraph adapter — Python-based ReAct agent with skills, tools, and plugins."""
import os
import logging
from molecule_runtime.adapters.base import BaseAdapter, AdapterConfig
from a2a.server.agent_execution import AgentExecutor
logger = logging.getLogger(__name__)
class LangGraphAdapter(BaseAdapter):
@staticmethod
def name() -> str:
return "langgraph"
@staticmethod
def display_name() -> str:
return "LangGraph"
@staticmethod
def description() -> str:
return "LangGraph ReAct agent — Python-based with skills, tools, plugins, and peer coordination"
@staticmethod
def get_config_schema() -> dict:
return {
"model": {"type": "string", "description": "LangChain model string (e.g. openrouter:google/gemini-2.5-flash)"},
"skills": {"type": "array", "items": {"type": "string"}, "description": "Skill folder names to load"},
"tools": {"type": "array", "items": {"type": "string"}, "description": "Built-in tools (web_search, filesystem, etc.)"},
}
def __init__(self):
self.loaded_skills = []
self.all_tools = []
self.system_prompt = None
async def setup(self, config: AdapterConfig) -> None:
result = await self._common_setup(config)
self.loaded_skills = result.loaded_skills
self.all_tools = result.langchain_tools
self.system_prompt = result.system_prompt
async def create_executor(self, config: AdapterConfig) -> AgentExecutor:
from molecule_runtime.agent import create_agent
from molecule_runtime.a2a_executor import LangGraphA2AExecutor
agent = create_agent(config.model, self.all_tools, self.system_prompt)
return LangGraphA2AExecutor(agent, heartbeat=config.heartbeat, model=config.model)
Adapter = LangGraphAdapter