> ## Documentation Index
> Fetch the complete documentation index at: https://novita.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Terminal interactivo (PTY)

export const SandboxConfigHint = () => {
  if (typeof document === "undefined") {
    return null;
  } else {
    return <Note>Before running the example code in this document, please ensure you have properly configured environment variables. For details, please refer to <a href="/docs/es/guides/sandbox-your-first-agent-sandbox#configure-environment-variables">Configure Environment Variables</a>.</Note>;
  }
};

El módulo PTY, o pseudoterminal, permite sesiones de terminal interactivas dentro del sandbox con comunicación bidireccional en tiempo real.

Una sesión PTY admite **streaming en tiempo real**, entregando la salida del terminal continuamente mediante callbacks a medida que se produce, y proporciona **entrada bidireccional**, lo que permite enviar datos mientras la sesión aún se está ejecutando. También ofrece una experiencia de **shell interactiva** con comportamiento completo de terminal, incluidos colores ANSI y secuencias de escape, y admite **persistencia de sesión**, por lo que una sesión en ejecución puede desconectarse y volver a conectarse más tarde.

<SandboxConfigHint />

## Crear una sesión PTY

Puedes usar `sandbox.pty.create()` para iniciar una shell bash interactiva.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Sandbox } from 'novita-sandbox/code-interpreter'

  const sandbox = await Sandbox.create()

  const terminal = await sandbox.pty.create({
    cols: 80,              // Terminal width in characters
    rows: 24,              // Terminal height in characters
    onData: (data) => {
      // Called whenever terminal outputs data
      process.stdout.write(data)
    },
    envs: { MY_VAR: 'hello' },  // Optional environment variables
    cwd: '/home/user',          // Optional working directory
    user: 'root',               // Optional user to run as
  })

  // terminal.pid contains the process ID
  console.log('Terminal PID:', terminal.pid)
  ```

  ```python Python icon="python" theme={"system"}
  import threading

  from novita_sandbox.code_interpreter import Sandbox, PtySize

  sandbox = Sandbox.create()

  terminal = sandbox.pty.create(
      size=PtySize(rows=24, cols=80),  # PtySize is (rows, cols)
      envs={'MY_VAR': 'hello'},        # Optional environment variables
      cwd='/home/user',                # Optional working directory
      user='root',                     # Optional user to run as
  )

  # terminal.pid contains the process ID
  print('Terminal PID:', terminal.pid)

  # The Python SDK has no on_data param. Output is streamed via wait(on_pty=...),
  # which blocks, so run it in a background thread.
  threading.Thread(
      target=lambda: terminal.wait(on_pty=lambda data: print(data.decode(), end='')),
      daemon=True,
  ).start()
  ```
</CodeGroup>

<Note>
  El PTY inicia una shell bash interactiva con `TERM=xterm-256color`, por lo que los colores ANSI y las secuencias de escape funcionan como se espera.
</Note>

## Tiempo de espera

La configuración de tiempo de espera es configurable y determina cuánto tiempo permanece activa la sesión PTY. Puedes mantener una sesión PTY abierta indefinidamente configurando `timeoutMs: 0` en JavaScript o `timeout=0` en Python. La sesión usa un tiempo de espera de 60 segundos de forma predeterminada.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Sandbox } from 'novita-sandbox/code-interpreter'

  const sandbox = await Sandbox.create()

  const terminal = await sandbox.pty.create({
    cols: 80,
    rows: 24,
    onData: (data) => process.stdout.write(data),
    timeoutMs: 0,  // Keep the session open indefinitely
  })
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox.code_interpreter import Sandbox, PtySize

  sandbox = Sandbox.create()

  terminal = sandbox.pty.create(
      size=PtySize(rows=24, cols=80),
      timeout=0,  # Keep the session open indefinitely
  )
  ```
</CodeGroup>

## Enviar entrada al PTY

Puedes usar `sendInput()` en JavaScript o `send_stdin()` en Python para enviar datos al terminal.

En JavaScript, `sendInput()` devuelve una Promise, y cualquier salida del terminal se entrega mediante el callback `onData` en lugar de devolverse directamente.
En Python, `send_stdin()` se completa de forma síncrona, y cualquier salida del terminal se entrega mediante el callback `on_pty` pasado a `wait()`.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Sandbox } from 'novita-sandbox/code-interpreter'

  const sandbox = await Sandbox.create()

  const terminal = await sandbox.pty.create({
    cols: 80,
    rows: 24,
    onData: (data) => process.stdout.write(data),
  })

  // Send a command (don't forget the newline!)
  await sandbox.pty.sendInput(
    terminal.pid,
    new TextEncoder().encode('echo "Hello from PTY"\n')
  )
  ```

  ```python Python icon="python" theme={"system"}
  import threading

  from novita_sandbox.code_interpreter import Sandbox, PtySize

  sandbox = Sandbox.create()

  terminal = sandbox.pty.create(size=PtySize(rows=24, cols=80))

  # Stream output in a background thread (Python uses wait(on_pty=...))
  threading.Thread(
      target=lambda: terminal.wait(on_pty=lambda data: print(data.decode(), end='')),
      daemon=True,
  ).start()

  # Send a command as bytes (b'...' is Python's byte string syntax)
  # Don't forget the newline!
  sandbox.pty.send_stdin(terminal.pid, b'echo "Hello from PTY"\n')
  ```
</CodeGroup>

## Cambiar el tamaño del terminal

Puedes usar `resize()` para notificar al PTY cuando el usuario cambie el tamaño de la ventana del terminal.
Los valores cols y rows representan las dimensiones del terminal en caracteres en lugar de píxeles.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Sandbox } from 'novita-sandbox/code-interpreter'

  const sandbox = await Sandbox.create()

  const terminal = await sandbox.pty.create({
    cols: 80,
    rows: 24,
    onData: (data) => process.stdout.write(data),
  })

  // Resize to new dimensions (in characters)
  await sandbox.pty.resize(terminal.pid, {
    cols: 120,
    rows: 40,
  })
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox.code_interpreter import Sandbox, PtySize

  sandbox = Sandbox.create()

  terminal = sandbox.pty.create(size=PtySize(rows=24, cols=80))

  # Resize to new dimensions (in characters)
  sandbox.pty.resize(terminal.pid, PtySize(rows=40, cols=120))
  ```
</CodeGroup>

## Desconectar y volver a conectar

Una sesión PTY puede permanecer activa incluso después de que el cliente se desconecte. Puedes desconectarte de la sesión y volver a conectarte más tarde con un nuevo manejador de datos.

Esto puede usarse para recuperarse de interrupciones de red, admitir acceso al terminal desde varios clientes y conservar el estado de la sesión entre reconexiones.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Sandbox } from 'novita-sandbox/code-interpreter'

  const sandbox = await Sandbox.create()

  // Create a PTY session
  const terminal = await sandbox.pty.create({
    cols: 80,
    rows: 24,
    onData: (data) => console.log('Handler 1:', new TextDecoder().decode(data)),
  })

  const pid = terminal.pid

  // Send a command
  await sandbox.pty.sendInput(pid, new TextEncoder().encode('echo hello\n'))

  // Disconnect - PTY keeps running in the background
  await terminal.disconnect()

  // Later: reconnect with a new data handler
  const reconnected = await sandbox.pty.connect(pid, {
    onData: (data) => console.log('Handler 2:', new TextDecoder().decode(data)),
  })

  // Continue using the session
  await sandbox.pty.sendInput(pid, new TextEncoder().encode('echo world\n'))

  // Wait for the terminal to exit
  await reconnected.wait()
  ```

  ```python Python icon="python" theme={"system"}
  import threading
  import time

  from novita_sandbox.code_interpreter import Sandbox, PtySize

  sandbox = Sandbox.create()

  # Create a PTY session
  terminal = sandbox.pty.create(size=PtySize(rows=24, cols=80))
  pid = terminal.pid

  # Send a command
  sandbox.pty.send_stdin(pid, b'echo hello\n')
  time.sleep(0.5)

  # Disconnect - PTY keeps running in the background.
  # Don't disconnect while a wait() is iterating the same handle.
  terminal.disconnect()

  # Later: reconnect with a new handle and stream its output
  reconnected = sandbox.pty.connect(pid)
  threading.Thread(
      target=lambda: reconnected.wait(on_pty=lambda data: print('Handler 2:', data.decode())),
      daemon=True,
  ).start()

  # Continue using the session
  sandbox.pty.send_stdin(pid, b'echo world\n')
  time.sleep(1.5)
  ```
</CodeGroup>

## Terminar el PTY

Puedes usar `kill()` para terminar la sesión PTY.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Sandbox } from 'novita-sandbox/code-interpreter'

  const sandbox = await Sandbox.create()

  const terminal = await sandbox.pty.create({
    cols: 80,
    rows: 24,
    onData: (data) => process.stdout.write(data),
  })

  // Kill the PTY
  const killed = await sandbox.pty.kill(terminal.pid)
  console.log('Killed:', killed)  // true if successful

  // Or use the handle method
  // await terminal.kill()
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox.code_interpreter import Sandbox, PtySize

  sandbox = Sandbox.create()

  terminal = sandbox.pty.create(size=PtySize(rows=24, cols=80))

  # Kill the PTY
  killed = sandbox.pty.kill(terminal.pid)
  print('Killed:', killed)  # True if successful

  # Or use the handle method
  # terminal.kill()
  ```
</CodeGroup>

## Esperar a que el PTY finalice

Puedes usar `wait()` para bloquear hasta que la sesión de terminal termine, por ejemplo cuando el usuario escriba `exit`.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Sandbox } from 'novita-sandbox/code-interpreter'

  const sandbox = await Sandbox.create()

  const terminal = await sandbox.pty.create({
    cols: 80,
    rows: 24,
    onData: (data) => process.stdout.write(data),
  })

  // Send exit command
  await sandbox.pty.sendInput(terminal.pid, new TextEncoder().encode('exit\n'))

  // Wait for the terminal to exit
  const result = await terminal.wait()
  console.log('Exit code:', result.exitCode)
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox.code_interpreter import Sandbox, PtySize

  sandbox = Sandbox.create()

  terminal = sandbox.pty.create(size=PtySize(rows=24, cols=80))

  # Send exit command
  sandbox.pty.send_stdin(terminal.pid, b'exit\n')

  # wait() blocks until the terminal exits; pass on_pty to stream output
  result = terminal.wait(on_pty=lambda data: print(data.decode(), end=''))
  print('Exit code:', result.exit_code)
  ```
</CodeGroup>

## Terminal interactivo (similar a SSH)

Puedes usar la misma API `sandbox.pty` descrita anteriormente para crear un terminal completamente interactivo como SSH, gestionando raw mode, el reenvío de stdin y los eventos de cambio de tamaño del terminal.
