
    ~h2                         d dl Z d dlZd dlZd dlZd dlmZ d dlmZmZm	Z	m
Z
 d dlZd dlZddlmZ ddlmZ ddlmZ  G d d	e      Zd
Zy)    N)BytesIO)AnyListOptionalTuple   )LogLevel)RemotePythonExecutor)
AgentErrorc                        e Zd ZdZ	 	 	 	 ddee   dedeee      deee      def
 fdZd Z	d	 Z
dd
ededeeef   fdZdee   dee   fdZd Zd Z xZS )PyodideDenoExecutora  
    Executes Python code securely in a sandboxed JavaScript environment using Pyodide and Deno.

    This executor leverages Deno's secure runtime and Pyodide to run Python code in a sandboxed
    environment within the browser's JavaScript engine. It provides strong isolation guarantees
    while still allowing Python code execution.

    Args:
        additional_imports (`list[str]`): Additional Python packages to install in the Pyodide environment.
        logger (`Logger`): Logger to use for output and errors.
        deno_path (`str`, optional): Path to the Deno executable. If not provided, will use "deno" from PATH.
        deno_permissions (`list[str]`, optional): List of permissions to grant to the Deno runtime.
            Default is minimal permissions needed for execution.
        pyodide_packages (`list[str]`, optional): Additional Pyodide packages to load.
        timeout (`int`, optional): Timeout in seconds for code execution. Default is 60 seconds.
    additional_imports	deno_pathdeno_permissionspyodide_packagestimeoutc                    t         |   ||       	 t        j                  |dgdd       || _        || _        |
g d| _	        n|D cg c]  }d| 	 c}| _	        |
g d| _
        n|| _
        | j                          | j                  |      | _        | j                  j                  dt         j"                  	       y # t        j                  t
        f$ r t        d      w xY wc c}w )
Nz	--versionT)capture_outputcheckzWDeno is not installed or not found in PATH. Please install Deno from https://deno.land/)z)--allow-net=cdn.jsdelivr.net,0.0.0.0:8000z--allow-readz--allow-writez--)numpypandas
matplotlibpillowzPyodideDenoExecutor is runninglevel)super__init__
subprocessrunSubprocessErrorFileNotFoundErrorRuntimeErrorr   r   r   r   _create_deno_runnerinstall_packagesinstalled_packagesloggerlogr	   INFO)	selfr   r&   r   r   r   r   perm	__class__s	           `/opt/mcp/mcp-sentiment/venv/lib/python3.12/site-packages/smolagents/pyodide_deno_executor.bak.pyr   zPyodideDenoExecutor.__init__2   s     	+V4	NNI{3DPTU # #%D! >N$NTr$[$ND! #$OD!$4D! 	  " #'"7"78J"K8NA **,=> 	i 	& %Os   C C,%C)c                 8   t        j                  d      | _        t        j                  j                  | j                  d      | _        t        | j                  d      5 }|j                  t               ddd       | j                          y# 1 sw Y   xY w)zNCreate the Deno JavaScript file that will run Pyodide and execute Python code.pyodide_deno_)prefixzpyodide_runner.jswN)tempfilemkdtemp
runner_dirospathjoinrunner_pathopenwriteJS_CODE_start_deno_server)r)   fs     r,   r#   z'PyodideDenoExecutor._create_deno_runnerb   ss    "**/B77<<9LM $""C( 	AGGG	 	!		 	s   !BBc                    | j                   dg| j                  z   | j                  gz   }t        j                  |t        j
                  t        j
                  d      | _        ddl}|j                  d       | j                  j                         2| j                  j                  j                         }t        d|       d| _        d	| _        	 t        j                  | j                        }|j                   d
k7  r%t        d|j                    d|j"                         y# t        j$                  $ r}t        d|       d}~ww xY w)z8Start the Deno server that will run our JavaScript code.r   T)stdoutstderrtextr   N   zFailed to start Deno server: zhttp://localhost:8765zhttp://localhost:8000   z"Server responded with status code : z"Failed to connect to Deno server: )r   r   r7   r   PopenPIPEserver_processtimesleeppollr?   readr"   
server_urlrequestsgetstatus_coder@   RequestException)r)   cmdrG   r?   responsees         r,   r;   z&PyodideDenoExecutor._start_deno_servern   s3   ~~u%(=(==AQAQ@RR )..????	
 	

1 ##%1((//446F!>vhGHH11	I||DOO4H##s*"%GH\H\G]]_`h`m`m_n#opp +(( 	I!CA3GHH	Is   AD( (E;E		Ecodereturn_final_answerreturnc                    	 ||| j                   | j                  z   d}t        j                  | j                  || j
                        }|j                  dk7  r#t        d|j                   | j                        |j                         }|j                  d      rQ|d   }|j                  dd       d|j                  d	d
       }d|v r|d|d    z  }t        || j                        |j                  dd      }|j                  d      }	t        |	t              rt|	j                  d      dk(  r`|	j                  dd      }
t        j                  |
j!                  d            }t"        j$                  j'                  t)        |            |fS |	|fS # t        j*                  $ r}t        d| | j                        d}~ww xY w)aO  
        Execute Python code in the Pyodide environment and return the result.

        Args:
            code (str): Python code to execute.
            return_final_answer (bool): Whether to extract and return the final answer.

        Returns:
            Tuple[Any, str]: A tuple containing the result and execution logs.
        )rS   returnFinalAnswerpackages)jsonr   rB   zServer error: errornameErrorrC   messagezUnknown errorstack
r>    resulttypeimagedatazutf-8z(Failed to communicate with Deno server: N)r   r%   rL   postrK   r   rN   r   r@   r&   rY   rM   
isinstancedictbase64	b64decodeencodePILImager8   r   rO   )r)   rS   rT   payloadrQ   result_datarZ   error_messageexecution_logsra   
image_datadecoded_bytesrR   s                r,   run_code_raise_errorsz)PyodideDenoExecutor.run_code_raise_errors   s   (	Z %8 11D4K4KKG  }}T__7DLLYH##s* >(--!A4;;OO #--/K w'#G,#(99VW#=">b9VeAf@g he#!r%.)9%::M << )__Xr:N !__X.F &$'FJJv,>',I#ZZ3
 & 0 01B1B71K Lyy~~gm&<=~MM>))(( 	ZGsKT[[YY	Zs   FF F G-GGc                     | j                   j                  ddj                  |       t        j                         |S )z
        Install additional Python packages in the Pyodide environment.

        Args:
            additional_imports (List[str]): List of package names to install.

        Returns:
            List[str]: List of installed packages.
        zAdding packages to load: z, r   )r&   r'   r6   r	   r(   )r)   r   s     r,   r$   z$PyodideDenoExecutor.install_packages   s8     	3DII>P4Q3RS[c[h[hi!!    c                 
   t        | d      rn| j                  rb| j                  j                  dt        j
                         | j                  j                          	 | j                  j                  d       t        | d      rJt        j                  j                  | j                        r ddl}|j!                  | j                         yyy# t        j                  $ r | j                  j                          Y w xY w)	z(Clean up resources used by the executor.rF   zStopping Deno server...r      )r   r3   r   N)hasattrrF   r&   r'   r	   r(   	terminatewaitr   TimeoutExpiredkillr4   r5   existsr3   shutilrmtree)r)   r~   s     r,   cleanupzPyodideDenoExecutor.cleanup   s    4)*t/B/BKKOO5X]]OK))++##(((3
 4&277>>$//+JMM$//* ,K&	 ,, +##((*+s   C -DDc                 $    | j                          y)zEnsure cleanup on deletion.N)r   )r)   s    r,   deletezPyodideDenoExecutor.delete   s    ru   )denoNN<   )F)__name__
__module____qualname____doc__r   strr   intr   r#   r;   boolr   r   rs   r$   r   r   __classcell__)r+   s   @r,   r   r       s    *  0404.O I.O 	.O
 #49-.O #49-.O .O`
"IB3Z# 3ZD 3ZUZ[^`c[cUd 3Zj"49 "c "+ ru   r   a  // pyodide_runner.js - Runs Python code in Pyodide within Deno
import { serve } from "https://deno.land/std/http/server.ts";
import { loadPyodide } from "npm:pyodide";


// Initialize Pyodide instance
const pyodidePromise = loadPyodide();
// Initialize Pyodide instance and load numpy
//const pyodidePromise = (async () => {
//  const pyodide = await loadPyodide();
//  await pyodide.loadPackage('numpy');
//  return pyodide;
//})();

// Function to execute Python code and return the result
async function executePythonCode(code, returnFinalAnswer = false) {
  //TODO:AVM:
  const pyodide = await pyodidePromise;
  //const pyodide = await pyodideReadyPromise;
  //let pyodide = await loadPyodide();

  //await pyodide.loadPackage('numpy');

  // Create a capture for stdout
  pyodide.runPython(`
    import sys
    import io
    sys.stdout = io.StringIO()
  `);

  // Execute the code and capture any errors
  let result = null;
  let error = null;
  let stdout = "";

  try {
    // Execute the code
    if (returnFinalAnswer) {
      // Extract the final_answer call if present
      const finalAnswerMatch = code.match(/final_answer\s*\((.*)\)/);
      if (finalAnswerMatch) {
        // Execute the code up to the final_answer call
        const preCode = code.replace(/final_answer\s*\(.*\)/, "");
        pyodide.runPython(preCode);

        // Execute the final_answer expression and get the result
        const finalAnswerExpr = finalAnswerMatch[1];
        result = pyodide.runPython(`${finalAnswerExpr}`);

        // Handle image results
        if (result && result.constructor.name === "Image") {
          // Convert PIL Image to base64
          const pngBytes = pyodide.runPython(`
            import io
            import base64
            buf = io.BytesIO()
            _result.save(buf, format='PNG')
            base64.b64encode(buf.getvalue()).decode('utf-8')
          `);
          result = { type: "image", data: pngBytes };
        }
      }
    } else {
      // Just run the code without expecting a final answer
      result = pyodide.runPython(code);
    }

    // Get captured stdout
    stdout = pyodide.runPython("sys.stdout.getvalue()");
  } catch (e) {
    error = {
      name: e.constructor.name,
      message: e.message,
      stack: e.stack
    };
  }

  return {
    result: result,
    stdout: stdout,
    error: error
  };
}

// Start a simple HTTP server to receive code execution requests
//const port = 8765;
//console.log(`Starting Pyodide server on port ${port}`);

serve(async (req) => {
  if (req.method === "POST") {
    try {
      const body = await req.json();
      const { code, returnFinalAnswer = false, packages = [] } = body;

      // Load any requested packages
      if (packages && packages.length > 0) {
        const pyodide = await pyodidePromise;
        //await pyodide.loadPackagesFromImports(code);
        for (const pkg of packages) {
          try {
            await pyodide.loadPackage(pkg);
          } catch (e) {
            console.error(`Failed to load package ${pkg}: ${e.message}`);
          }
        }
      } else {
        console.log("Skipping package loading block. Packages:", packages); // Added log for else case
      }
      //const pyodide = await pyodidePromise;
      //await pyodide.loadPackage("numpy");

      const result = await executePythonCode(code, returnFinalAnswer);
      return new Response(JSON.stringify(result), {
        headers: { "Content-Type": "application/json" }
      });
    } catch (e) {
      return new Response(JSON.stringify({ error: e.message }), {
        status: 500,
        headers: { "Content-Type": "application/json" }
      });
    }
  }

  return new Response("Pyodide-Deno Executor is running. Send POST requests with code to execute.", {
    headers: { "Content-Type": "text/plain" }
  });
});
)rh   r4   r   r1   ior   typingr   r   r   r   	PIL.Imagerk   rL   
monitoringr	   remote_executorsr
   utilsr   r   r:    ru   r,   <module>r      sC   "  	    - -     2 E. EP@ru   