Skip to main content
The WebSocket terminal provides interactive, real-time access to a PTY (pseudo-terminal) in your sandbox. This enables you to run interactive commands, monitor output in real-time, and handle terminal-specific features like resizing.

Prerequisites

Before you begin, make sure you have:
  • Active sandbox - A running sandbox (see Creating Sandboxes)
  • WebSocket library - For Python: pip install websockets (for JavaScript, WebSocket is built-in)
  • Understanding of async/await - Familiarity with asynchronous programming patterns
  • Terminal access - Basic understanding of terminal/command-line operations

Overview

The WebSocket terminal is ideal for:
  • Interactive command-line tools and REPLs
  • Real-time monitoring of long-running processes
  • Terminal applications that require PTY support
  • Building terminal UIs or dashboards
  • Debugging and troubleshooting
The WebSocket terminal requires the websockets library for Python. Install it with: pip install websockets

Connecting to Terminal

Connect to the terminal using the terminal resource:
  • Python
  • JavaScript
from hopx_ai import Sandbox
import asyncio

async def connect_terminal():
    sandbox = Sandbox.create(template="code-interpreter")
    
    # Connect to terminal
    async with await sandbox.terminal.connect() as ws:
        # Terminal is ready for input
        pass
    
    # Clean up
    sandbox.kill()

asyncio.run(connect_terminal())

Sending Input

Send commands and input to the terminal:
  • Python
  • JavaScript
async def send_commands():
    sandbox = Sandbox.create(template="code-interpreter")
    
    async with await sandbox.terminal.connect() as ws:
        # Send a command (include \n to execute)
        await sandbox.terminal.send_input(ws, "ls -la\n")
        
        # Send another command
        await sandbox.terminal.send_input(ws, "cd /workspace\n")
        
        # Send interactive input
        await sandbox.terminal.send_input(ws, "python3\n")
        await sandbox.terminal.send_input(ws, "print('Hello')\n")
        await sandbox.terminal.send_input(ws, "exit()\n")
    
    sandbox.kill()

asyncio.run(send_commands())

Receiving Output

Receive terminal output in real-time using async iteration:
  • Python
  • JavaScript
async def receive_output():
    sandbox = Sandbox.create(template="code-interpreter")
    
    async with await sandbox.terminal.connect() as ws:
        # Send command
        await sandbox.terminal.send_input(ws, "echo 'Hello World'\n")
        
        # Receive output
        async for message in sandbox.terminal.iter_output(ws):
            if message['type'] == 'output':
                print(message['data'], end='')
            elif message['type'] == 'exit':
                print(f"\nProcess exited with code: {message['code']}")
                break
    
    sandbox.kill()

asyncio.run(receive_output())

Resizing Terminal

Resize the terminal window to match your display:
  • Python
  • JavaScript
async def resize_terminal():
    sandbox = Sandbox.create(template="code-interpreter")
    
    async with await sandbox.terminal.connect() as ws:
        # Resize to 120 columns, 40 rows
        await sandbox.terminal.resize(ws, cols=120, rows=40)
        
        # Send command that benefits from larger terminal
        await sandbox.terminal.send_input(ws, "ls -la\n")
        
        async for message in sandbox.terminal.iter_output(ws):
            if message['type'] == 'output':
                print(message['data'], end='')
            elif message['type'] == 'exit':
                break
    
    sandbox.kill()

asyncio.run(resize_terminal())

Complete Example

Here’s a complete example that demonstrates interactive terminal usage:
  • Python
  • JavaScript
from hopx_ai import Sandbox
import asyncio

async def interactive_terminal():
    sandbox = Sandbox.create(template="code-interpreter")
    
    try:
        async with await sandbox.terminal.connect() as ws:
            # Resize terminal
            await sandbox.terminal.resize(ws, cols=80, rows=24)
            
            # Run a series of commands
            commands = [
                "pwd\n",
                "whoami\n",
                "uname -a\n",
                "python3 --version\n"
            ]
            
            for cmd in commands:
                await sandbox.terminal.send_input(ws, cmd)
                
                # Receive output for this command
                async for message in sandbox.terminal.iter_output(ws):
                    if message['type'] == 'output':
                        print(message['data'], end='')
                    elif message['type'] == 'exit':
                        # Command completed, move to next
                        break
                
                print()  # Blank line between commands
    
    finally:
        sandbox.kill()

asyncio.run(interactive_terminal())

Message Types

The terminal sends different message types:
  • output: Terminal output data
    {"type": "output", "data": "command output text"}
    
  • exit: Process exit notification
    {"type": "exit", "code": 0}
    

Error Handling

Handle connection errors and timeouts:
  • Python
  • JavaScript
import asyncio
from hopx_ai import Sandbox

async def terminal_with_error_handling():
    sandbox = Sandbox.create(template="code-interpreter")
    
    try:
        async with await sandbox.terminal.connect(timeout=30) as ws:
            await sandbox.terminal.send_input(ws, "invalid-command-that-fails\n")
            
            async for message in sandbox.terminal.iter_output(ws):
                if message['type'] == 'output':
                    print(message['data'], end='')
                elif message['type'] == 'exit':
                    exit_code = message['code']
                    if exit_code != 0:
                        print(f"\nCommand failed with exit code: {exit_code}")
                    break
    
    except Exception as e:
        print(f"Terminal error: {e}")
    
    finally:
        sandbox.kill()

asyncio.run(terminal_with_error_handling())

Best Practices

Use async context managers in Python to ensure proper WebSocket cleanup. The async with statement automatically closes the connection.
Include newline characters (\n) when sending commands to execute them immediately. Without \n, the command waits for more input.
Terminal connections are stateful. Each connection maintains its own shell session. If you need a fresh environment, create a new terminal connection.
Resize the terminal before running commands that format output based on terminal width (like ls -la or tree).

API Reference

Python SDK

  • sandbox.terminal.connect(*, timeout=30) - Connect to terminal WebSocket
  • sandbox.terminal.send_input(ws, data) - Send input to terminal
  • sandbox.terminal.resize(ws, cols, rows) - Resize terminal window
  • sandbox.terminal.iter_output(ws) - Async iterator for terminal messages

JavaScript SDK

  • sandbox.terminal.connect() - Connect to terminal WebSocket
  • sandbox.terminal.sendInput(ws, data) - Send input to terminal
  • sandbox.terminal.resize(ws, cols, rows) - Resize terminal window
  • sandbox.terminal.output(ws) - Async iterator for terminal messages

API Endpoint

  • WebSocket: /terminal - Connect to interactive terminal
  • Message Types: input, resize, output, exit

Next Steps