Skip to main content
Learn how to build an AI code interpreter that safely executes user-provided code in isolated sandboxes, similar to ChatGPT’s code interpreter feature.

Overview

An AI code interpreter allows users to write and execute code in a safe, isolated environment. This tutorial shows you how to:
  • Create sandboxes for code execution
  • Execute Python and JavaScript code safely
  • Handle errors and stream output
  • Capture rich outputs (plots, images, tables)
  • Clean up resources automatically

Prerequisites

  • Python SDK installed (pip install hopx-ai)
  • API key configured (see Authentication)
  • Basic understanding of Python async/await

Step 1: Basic Code Execution

Start with a simple code execution function:
  • Python
  • JavaScript/TypeScript
from hopx_ai import Sandbox

def execute_code(code: str, language: str = "python"):
    """Execute code in an isolated sandbox"""
    with Sandbox.create(template="code-interpreter") as sandbox:
        result = sandbox.run_code(code, language=language)
        return {
            "stdout": result.stdout,
            "stderr": result.stderr,
            "success": result.success,
            "exit_code": result.exit_code
        }

# Example usage
result = execute_code("print('Hello, World!')")
print(result["stdout"])  # Hello, World!

Step 2: Add Error Handling

Handle errors gracefully:
  • Python
  • JavaScript/TypeScript
from hopx_ai import Sandbox
from hopx_ai.errors import HopxError, CodeExecutionError

def execute_code_safe(code: str, language: str = "python"):
    """Execute code with comprehensive error handling"""
    try:
        with Sandbox.create(template="code-interpreter") as sandbox:
            result = sandbox.run_code(code, language=language)
            
            if not result.success:
                return {
                    "success": False,
                    "error": result.stderr,
                    "exit_code": result.exit_code
                }
            
            return {
                "success": True,
                "output": result.stdout,
                "rich_outputs": result.rich_outputs if hasattr(result, 'rich_outputs') else []
            }
    except CodeExecutionError as e:
        return {
            "success": False,
            "error": f"Code execution failed: {str(e)}",
            "request_id": getattr(e, 'request_id', None)
        }
    except HopxError as e:
        return {
            "success": False,
            "error": f"Sandbox error: {str(e)}",
            "request_id": getattr(e, 'request_id', None)
        }

Step 3: Stream Output in Real-Time

Stream execution output for better user experience:
  • Python
  • JavaScript/TypeScript
import asyncio
from hopx_ai import Sandbox

async def stream_code_execution(code: str):
    """Stream code execution output in real-time"""
    sandbox = Sandbox.create(template="code-interpreter")
    
    try:
        async for message in sandbox.run_code_stream(code):
            if message['type'] == 'stdout':
                yield {'type': 'output', 'data': message['data']}
            elif message['type'] == 'stderr':
                yield {'type': 'error', 'data': message['data']}
            elif message['type'] == 'result':
                yield {
                    'type': 'complete',
                    'exit_code': message['exit_code'],
                    'success': message['exit_code'] == 0
                }
    finally:
        sandbox.kill()

# Usage with async generator
async def main():
    code = """
import time
for i in range(5):
    print(f"Step {i+1}/5")
    time.sleep(1)
"""
    async for event in stream_code_execution(code):
        print(event)

asyncio.run(main())

Step 4: Capture Rich Outputs

Capture plots, images, and DataFrames automatically:
  • Python
  • JavaScript/TypeScript
from hopx_ai import Sandbox

def execute_with_rich_outputs(code: str):
    """Execute code and capture rich outputs (plots, images, tables)"""
    with Sandbox.create(template="code-interpreter") as sandbox:
        result = sandbox.run_code(code)
        
        outputs = {
            "stdout": result.stdout,
            "stderr": result.stderr,
            "success": result.success
        }
        
        # Capture rich outputs if available
        if hasattr(result, 'rich_outputs') and result.rich_outputs:
            outputs["rich_outputs"] = []
            for rich in result.rich_outputs:
                if rich.type == "image":
                    # Download image
                    image_data = sandbox.files.read(rich.path)
                    outputs["rich_outputs"].append({
                        "type": "image",
                        "data": image_data,
                        "mime_type": rich.mime_type
                    })
                elif rich.type == "dataframe":
                    outputs["rich_outputs"].append({
                        "type": "dataframe",
                        "data": rich.data
                    })
        
        return outputs

# Example: Generate a plot
code = """
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 100)
y = np.sin(x)

plt.figure(figsize=(10, 6))
plt.plot(x, y)
plt.title('Sine Wave')
plt.savefig('/workspace/plot.png')
print("Plot saved!")
"""

result = execute_with_rich_outputs(code)
# result["rich_outputs"] will contain the plot image

Step 5: Complete Implementation

Here’s a complete AI code interpreter class:
  • Python
  • JavaScript/TypeScript
from hopx_ai import Sandbox
    from hopx_ai.errors import HopxError, CodeExecutionError
from typing import Dict, Any, Optional
import asyncio

class AICodeInterpreter:
    """AI Code Interpreter using Hopx Sandboxes"""
    
    def __init__(self, template: str = "code-interpreter"):
        self.template = template
    
        def execute(
        self,
        code: str,
        language: str = "python",
        timeout: int = 30,
        env_vars: Optional[Dict[str, str]] = None
    ) -> Dict[str, Any]:
        """Execute code and return results"""
        sandbox = None
        try:
            sandbox = Sandbox.create(
                template=self.template,
                env_vars=env_vars or {}
            )
            
                result = sandbox.run_code(
                code,
                language=language,
                timeout=timeout
            )
            
            response = {
                "success": result.success,
                "stdout": result.stdout,
                "stderr": result.stderr,
                "exit_code": result.exit_code
            }
            
            # Add rich outputs if available
            if hasattr(result, 'rich_outputs'):
                response["rich_outputs"] = result.rich_outputs
            
            return response
            
        except CodeExecutionError as e:
            return {
                "success": False,
                    "error": f"Code execution failed: {str(e)}",
                    "request_id": getattr(e, 'request_id', None)
            }
            except HopxError as e:
            return {
                "success": False,
                    "error": f"Sandbox error: {str(e)}",
                    "request_id": getattr(e, 'request_id', None)
            }
        finally:
            if sandbox:
                sandbox.kill()
    
    async def stream_execute(
        self,
        code: str,
        language: str = "python",
        timeout: int = 30
    ):
        """Stream code execution output"""
        sandbox = None
        try:
            sandbox = Sandbox.create(template=self.template)
            
            async for message in sandbox.run_code_stream(code, language=language, timeout=timeout):
                yield message
                
        finally:
            if sandbox:
                sandbox.kill()

# Usage
async def main():
    interpreter = AICodeInterpreter()
    
    # Execute code
        result = interpreter.execute("""
import pandas as pd
import numpy as np

data = pd.DataFrame({
    'x': np.random.randn(100),
    'y': np.random.randn(100)
})

print(data.describe())
""")
    
    print(result)

asyncio.run(main())

Best Practices

Always delete sandboxes after use to avoid unnecessary costs:
  • Python
  • JavaScript/TypeScript
# Use context manager (automatic cleanup)
with Sandbox.create(template="code-interpreter") as sandbox:
    result = sandbox.run_code(code)
# Sandbox automatically deleted
Always set reasonable timeouts to prevent hanging executions:
result = sandbox.run_code(code, timeout=30)  # 30 seconds max
Provide clear error messages to users:
try:
    result = sandbox.run_code(code)
except CodeExecutionError as e:
    return {"error": f"Code execution failed: {e.message}"}
Create a new sandbox for each user session to ensure isolation:
# ❌ Bad: Reusing sandbox
# sandbox = Sandbox.create(...)
# result1 = sandbox.run_code(user1_code)
# result2 = sandbox.run_code(user2_code)  # Security risk!

# ✅ Good: New sandbox per user
with Sandbox.create(...) as sandbox:
    result = sandbox.run_code(user_code)

Next Steps