import importlib from langchain.tools import StructuredTool from langchain_core.tools import ToolException from langchain_experimental.utilities import PythonREPL from loguru import logger from pydantic import BaseModel, Field from langflow.base.langchain_utilities.model import LCToolComponent from langflow.field_typing import Tool from langflow.inputs import StrInput from langflow.schema import Data class PythonREPLToolComponent(LCToolComponent): display_name = "Python REPL" description = "A tool for running Python code in a REPL environment." name = "PythonREPLTool" icon = "Python" inputs = [ StrInput( name="name", display_name="Tool Name", info="The name of the tool.", value="python_repl", ), StrInput( name="description", display_name="Tool Description", info="A description of the tool.", value="A Python shell. Use this to execute python commands. " "Input should be a valid python command. " "If you want to see the output of a value, you should print it out with `print(...)`.", ), StrInput( name="global_imports", display_name="Global Imports", info="A comma-separated list of modules to import globally, e.g. 'math,numpy'.", value="math", ), StrInput( name="code", display_name="Python Code", info="The Python code to execute.", value="print('Hello, World!')", ), ] class PythonREPLSchema(BaseModel): code: str = Field(..., description="The Python code to execute.") def get_globals(self, global_imports: str | list[str]) -> dict: global_dict = {} if isinstance(global_imports, str): modules = [module.strip() for module in global_imports.split(",")] elif isinstance(global_imports, list): modules = global_imports else: msg = "global_imports must be either a string or a list" raise TypeError(msg) for module in modules: try: imported_module = importlib.import_module(module) global_dict[imported_module.__name__] = imported_module except ImportError as e: msg = f"Could not import module {module}" raise ImportError(msg) from e return global_dict def build_tool(self) -> Tool: globals_ = self.get_globals(self.global_imports) python_repl = PythonREPL(_globals=globals_) def run_python_code(code: str) -> str: try: return python_repl.run(code) except Exception as e: logger.opt(exception=True).debug("Error running Python code") raise ToolException(str(e)) from e tool = StructuredTool.from_function( name=self.name, description=self.description, func=run_python_code, args_schema=self.PythonREPLSchema, ) self.status = f"Python REPL Tool created with global imports: {self.global_imports}" return tool def run_model(self) -> list[Data]: tool = self.build_tool() result = tool.run(self.code) return [Data(data={"result": result})]