Skip to content

Tools

BaseTool

nirvana.executors.tools.BaseTool(**kwargs)

Bases: ABC

Source code in nirvana/executors/tools.py
def __init__(self, **kwargs):
    for key, value in kwargs.items():
        setattr(self, key, value)

Attributes

name: str instance-attribute
description: str instance-attribute

Functions

__call__(*args, **kwds) -> Any abstractmethod
Source code in nirvana/executors/tools.py
@abstractmethod
def __call__(self, *args, **kwds) -> Any:
    pass

FunctionCallTool

nirvana.executors.tools.FunctionCallTool(name: str | None = None, func: Callable | None = None, coroutine: Callable[..., Awaitable[Any]] | None = None, **kwargs)

Bases: BaseTool

Source code in nirvana/executors/tools.py
def __init__(
    self,
    name: str | None = None,
    func: Callable | None = None,
    coroutine: Callable[..., Awaitable[Any]] | None = None,
    **kwargs
):
    self.name = name
    self.func = func
    self.coroutine = coroutine

Attributes

description = 'This is a tool that evaluates python code. It can be used to perform calculations.' class-attribute instance-attribute
name = name instance-attribute
func = func instance-attribute
coroutine = coroutine instance-attribute

Functions

__repr__() -> str
Source code in nirvana/executors/tools.py
def __repr__(self) -> str:
    return f"FunctionCall(name={self.name})"
__str__() -> str
Source code in nirvana/executors/tools.py
def __str__(self) -> str:
    return self.__repr__()
from_function(func: Callable | None = None, coroutine: Callable[..., Awaitable[Any]] | None = None, name: str | None = None) classmethod
Source code in nirvana/executors/tools.py
@classmethod
def from_function(
    cls,
    func: Callable | None = None,
    coroutine: Callable[..., Awaitable[Any]] | None = None,
    name: str | None = None,
):
    if func is not None:
        func = func
    elif coroutine is not None:
        func = coroutine
    else:
        raise ValueError("Either `func` or `coroutine` must be provided.")

    name = name or func.__name__

    return cls(
        name=name,
        func=func,
        coroutine=coroutine
    )
__call__(*args, **kwargs)
Source code in nirvana/executors/tools.py
def __call__(self, *args, **kwargs):
    if self.func is not None:
        return self._run(*args, **kwargs)
    elif self.coroutine is not None:
        return self._arun(*args, **kwargs)

PythonInterpreterTool

nirvana.executors.tools.PythonInterpreterTool(authorized_imports: list[str] | None = None, max_print_outputs_length: int = 50000, **kwargs)

Bases: BaseTool

Source code in nirvana/executors/tools.py
def __init__(
    self,
    authorized_imports: list[str] | None = None,
    max_print_outputs_length: int = 50_000,
    **kwargs
):
    self.authorized_imports = authorized_imports or []
    self.max_print_outputs_length = max_print_outputs_length
    # Prepare a minimal, safe builtins dict
    self._safe_builtins = DEFAULT_BUILTINS

Attributes

name = 'python_interpreter' class-attribute instance-attribute
description = 'Python Interpreter that runs code in a sandboxed environment' class-attribute instance-attribute
authorized_imports = authorized_imports or [] instance-attribute
max_print_outputs_length = max_print_outputs_length instance-attribute

Functions

execute(code: str, variables: dict[str, Any] | None = None) -> str

Execute Python code in a sandboxed environment.

  • Captures anything printed via print.
  • If the final statement is an expression and evaluates to a non-None value, that value is printed (like a REPL).
  • Returns the full captured stdout as a string (possibly truncated).
Source code in nirvana/executors/tools.py
def execute(self, code: str, variables: dict[str, Any] | None = None) -> str:
    """
    Execute Python code in a sandboxed environment.

    - Captures anything printed via `print`.
    - If the final statement is an expression and evaluates to a non-None
      value, that value is printed (like a REPL).
    - Returns the full captured stdout as a string (possibly truncated).
    """
    variables = variables or {}

    # Parse and validate the code first
    try:
        tree = ast.parse(code, mode="exec")
    except SyntaxError as e:
        return f"SyntaxError: {e}"

    self._validate_imports(tree)

    body = tree.body
    pre_body = body[:-1] if body else []
    last_stmt = body[-1] if body else None

    stdout_buffer = io.StringIO()
    globals_env: dict[str, Any] = {"__builtins__": self._safe_builtins}
    locals_env: dict[str, Any] = dict(variables)

    with redirect_stdout(stdout_buffer):
        # Execute all but the last statement
        if pre_body:
            pre_module = ast.Module(body=pre_body, type_ignores=[])
            exec(compile(pre_module, "<sandbox>", "exec"), globals_env, locals_env)

        # Handle the last statement specially to mimic REPL behaviour
        if last_stmt is not None:
            if isinstance(last_stmt, ast.Expr):
                expr = ast.Expression(last_stmt.value)
                result = eval(compile(expr, "<sandbox>", "eval"), globals_env, locals_env)
                if result is not None:
                    # Print the result so it appears in the captured output
                    print(result)
            else:
                last_module = ast.Module(body=[last_stmt], type_ignores=[])
                exec(
                    compile(last_module, "<sandbox>", "exec"),
                    globals_env,
                    locals_env,
                )

    output = stdout_buffer.getvalue()
    if len(output) > self.max_print_outputs_length:
        output = output[: self.max_print_outputs_length] + "\n... [truncated]"
    return output
__enter__()
Source code in nirvana/executors/tools.py
def __enter__(self):
    return self
__call__(code: str, variables: dict[str, Any] | None = None) -> str
Source code in nirvana/executors/tools.py
def __call__(self, code: str, variables: dict[str, Any] | None = None) -> str:
    return self.execute(code, variables)
__exit__(exc_type, exc_value, traceback)
Source code in nirvana/executors/tools.py
def __exit__(self, exc_type, exc_value, traceback):
    # No external resources to clean up for now, but we keep this
    # method to support context manager usage.
    return False