File size: 1,940 Bytes
e9aced8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
"""Python REPL tool para ejecutar cálculos y análisis de datos."""
import io
import contextlib
import traceback
from langchain_core.tools import tool


# Estado persistente entre llamadas (mismo namespace en la sesión)
_repl_globals: dict = {}


@tool
def python_repl(code: str) -> str:
    """Ejecuta código Python. Usa print() para ver resultados. Disponible: pandas, numpy, math, json."""
    # Preparar librerías comunes en el namespace si es la primera vez
    if not _repl_globals:
        try:
            import math, json, datetime
            import pandas as pd
            _repl_globals.update({
                "math": math,
                "json": json,
                "datetime": datetime,
                "pd": pd,
                "__builtins__": __builtins__,
            })
            try:
                import numpy as np
                _repl_globals["np"] = np
            except ImportError:
                pass
        except Exception as e:
            return f"Error inicializando REPL: {e}"

    import re as _re
    # Strip markdown code fences the LLM sometimes adds
    code = _re.sub(r"^```(?:python)?\n?", "", code.strip())
    code = _re.sub(r"\n?```$", "", code.strip())

    stdout_buffer = io.StringIO()
    stderr_buffer = io.StringIO()

    try:
        with contextlib.redirect_stdout(stdout_buffer), \
             contextlib.redirect_stderr(stderr_buffer):
            exec(code, _repl_globals)

        stdout = stdout_buffer.getvalue()
        stderr = stderr_buffer.getvalue()

        if stderr:
            return f"STDERR:\n{stderr}\n\nSTDOUT:\n{stdout}" if stdout else f"STDERR:\n{stderr}"

        return stdout if stdout else "(ejecutado sin output — usa print() para ver resultados)"
    except Exception:
        return f"Error ejecutando código:\n{traceback.format_exc()}"


def reset_repl():
    """Limpia el estado del REPL (útil para tests)."""
    _repl_globals.clear()