SandboxesReferencia del SDK

Referencia de la API y el SDK de Sandbox

Lizard SDK es el cliente de Sandboxes en Lizard (lizard.build): @lizard-build/sdk en npm para TypeScript y JavaScript, y lizard-sdk en PyPI para Python, que se importa como lizard. Ambos llaman a la misma API HTTP. Esta página enumera cada llamada de sandbox por su nombre en TypeScript y en Python, con ejemplos en ambos lenguajes. Para una primera ejecución guiada, usa el inicio rápido; para saber qué son los Sandboxes, lee la descripción general.

Instalar y autenticar

npm install @lizard-build/sdk
pip install lizard-sdk
export LIZARD_API_KEY="<your-api-key>"

Crea una clave API en Settings → API keys o con lizard keys create <name>. El SDK lee LIZARD_API_KEY; pasa apiKey (Python: api_key) para usar otra clave. Cada sandbox necesita un proyecto: pasa projectId (Python: project_id) o resuelve su ID, slug o nombre con project.

Opciones de creación

TypeScriptPython
projectId / projectproject_id / project
timeoutMstimeout_ms
regionregion
volumeName / volumeIdvolume_name / volume_id
sizesize
snapshotIdsnapshot_id
envsenvs
metadatametadata
lizardTokenlizard_token
apiKeyapi_key
import { Sandbox } from '@lizard-build/sdk';
 
const sandbox = await Sandbox.create('base', {
  projectId: 'proj_123',
  size: 'small',
  timeoutMs: 10 * 60 * 1000,
  envs: { MODE: 'test' },
  metadata: { task: 'report-42' },
});
from lizard import Sandbox
 
sandbox = Sandbox.create(
    "base",
    project_id="proj_123",
    size="small",
    timeout_ms=10 * 60 * 1000,
    envs={"MODE": "test"},
    metadata={"task": "report-42"},
)
  • El primer argumento es una plantilla del catálogo de runtime y plantillas. Sin él, el SDK arranca base.
  • size es 'small', 'medium' o 'large': 2 vCPU / 4 GB, 4 vCPU / 8 GB (el predeterminado) u 8 vCPU / 16 GB; consulta tamaños y precios. size no se aplica a un sandbox restaurado desde un snapshot; se ejecuta con el tamaño de su origen.
  • timeoutMs es 300000 por defecto, cinco minutos. 0 desactiva la caducidad. Consulta recursos y duración.
  • Indica la región de forma explícita si hace falta; que aparezca en el catálogo no garantiza capacidad libre. No indiques region cuando adjuntes un volumen: el sandbox se ejecuta donde está el volumen.
  • metadata son tus propias etiquetas; getInfo() y list() las devuelven.
  • lizardToken escribe una clave API liz_ dentro del sandbox para que lizard funcione en él. Cualquier proceso del sandbox puede leer esa clave, así que pasa una limitada al workspace.

Métodos

TypeScriptPythonQué hace
Sandbox.create(template, options)Sandbox.create(template, ...)Crear en un proyecto desde una plantilla del catálogo.
Sandbox.connect(sandboxId)Sandbox.connect(sandbox_id)Conectar a un sandbox existente; no reanuda.
Sandbox.list({ projectId })Sandbox.list(project_id=...)Listar Sandboxes accesibles; comprobar su estado.
sandbox.getInfo()sandbox.get_info()Obtener estado, runtime y metadatos.
sandbox.process.exec(cmd, opts)sandbox.process.exec_(cmd, ...)Ejecutar un comando de shell o un array argv; devolver stdout, stderr y el código de salida.
sandbox.process.list()sandbox.process.list()Listar los procesos iniciados con exec.
sandbox.process.kill(pid, signal)sandbox.process.kill(pid, signal)Enviar una señal a un proceso y a sus hijos; SIGTERM por defecto.
sandbox.fs.write(path, data)sandbox.fs.write(path, data)Escribir texto o bytes; crear directorios superiores.
sandbox.fs.read(path)sandbox.fs.read(path)Leer texto UTF-8.
sandbox.fs.readBytes(path)sandbox.fs.read_bytes(path)Leer los bytes de un archivo.
sandbox.fs.list(path)sandbox.fs.list(path)Listar un directorio.
sandbox.fs.stat(path)sandbox.fs.stat(path)Devolver tipo, tamaño, modo, propietario y fecha de modificación.
sandbox.fs.makeDir(path)sandbox.fs.make_dir(path)Crear un directorio y los superiores que falten.
sandbox.fs.move(from, to)sandbox.fs.move(src, dst)Mover un archivo o directorio.
sandbox.fs.remove(path)sandbox.fs.remove(path)Eliminar un archivo o directorio.
sandbox.exposePort(port)sandbox.expose_port(port)Publicar un puerto; devolver url, hostname y el token de acceso.
sandbox.getHost(port)sandbox.get_host(port)Publicar un puerto y devolver su hostname; las solicitudes necesitan sandbox.accessToken.
sandbox.unexpose(port)sandbox.unexpose(port)Retirar un puerto publicado.
sandbox.setTimeout(ms)sandbox.set_timeout(ms)Fijar la duración restante, mínimo 1000 ms.
sandbox.pause() / sandbox.resume()sandbox.pause() / sandbox.resume()Poner en cola una pausa o reanudación y responder al instante.
sandbox.waitForStatus(status)sandbox.wait_for_status(status)Esperar a paused o running; lanzar un error si falla la pausa.
sandbox.fork({ count })sandbox.fork(count=...)Copiar un sandbox en marcha de 1 a 10 veces, incluidos la memoria y los procesos.
sandbox.snapshot(name, { poolSize })sandbox.snapshot(name, pool_size=...)Guardar la memoria y los archivos de /workspace en un snapshot privado.
Sandbox.waitForSnapshot(snapshotId)Sandbox.wait_for_snapshot(snapshot_id)Esperar a que el snapshot esté listo.
Sandbox.restore(snapshotId)Sandbox.restore(snapshot_id)Iniciar un sandbox nuevo desde un snapshot.
Sandbox.deleteSnapshot(snapshotId)Sandbox.delete_snapshot(snapshot_id)Eliminar un snapshot; los sandboxes restaurados desde él siguen en marcha.
sandbox.kill()sandbox.kill()Detener el sandbox y separar su volumen.

Ejecutar comandos

process.exec (Python: exec_) ejecuta un comando y espera a que termine. Pasa onStdout u onStderr (Python: on_stdout, on_stderr) para recibir la salida mientras se ejecuta el comando; la llamada igualmente devuelve el resultado completo al final. Pasa un array argv en lugar de una cadena para evitar la shell, que es la forma segura de pasar texto no confiable como argumento.

const result = await sandbox.process.exec('npm test', {
  workdir: '/app',
  envs: { NODE_ENV: 'test' },
  timeoutMs: 120_000,
  onStdout: (chunk) => process.stdout.write(chunk),
});
if (result.exitCode !== 0) throw new Error(result.stderr);
 
await sandbox.process.exec(['grep', '-rn', '--', userQuery, '/workspace']);
result = sandbox.process.exec_(
    "npm test",
    workdir="/app",
    envs={"NODE_ENV": "test"},
    timeout_ms=120_000,
    on_stdout=lambda chunk: print(chunk, end=""),
)
if result.exit_code != 0:
    raise RuntimeError(result.stderr)
 
sandbox.process.exec_(["grep", "-rn", "--", user_query, "/workspace"])

Los resultados incluyen stdout, stderr y el código de salida. Un código de salida distinto de cero es un resultado que debes comprobar; los fallos de la solicitud lanzan una excepción. El tiempo máximo de un comando está entre 1 y 600 segundos. process.exec acepta envs, workdir y user; los comandos se ejecutan como root salvo que pases user. Las envs de creación llegan a todos los comandos en un sandbox Firecracker; un sandbox de pod las ignora, así que allí pásalas en cada comando.

Archivos

fs.write escribe texto o bytes; fs.read lee texto. Para archivos binarios, escribe bytes y vuelve a leerlos con fs.readBytes (Python: read_bytes). Usa rutas absolutas. Una ruta que no existe lanza NotFoundError.

await sandbox.fs.write('/app/data.csv', 'x,y\n1,2\n');
const text = await sandbox.fs.read('/app/data.csv');
const entries = await sandbox.fs.list('/app');
const png = await sandbox.fs.readBytes('/app/chart.png');
sandbox.fs.write("/app/data.csv", "x,y\n1,2\n")
text = sandbox.fs.read("/app/data.csv")
entries = sandbox.fs.list("/app")
png = sandbox.fs.read_bytes("/app/chart.png")

Los archivos fuera de un volumen de Persistent Volumes en /workspace desaparecen cuando el sandbox se detiene.

Puertos

Inicia un servidor en 0.0.0.0 dentro del sandbox y luego publica su puerto. Cada solicitud necesita el token de acceso, en la cabecera X-Lizard-Access-Token o una vez como ?lizard_token= en un navegador. Consulta URLs de vista previa.

const { url, hostname, accessToken } = await sandbox.exposePort(3000);
console.log(url); // open in a browser; it carries the token
await fetch(`https://${hostname}/api`, { headers: { 'X-Lizard-Access-Token': accessToken } });
await sandbox.unexpose(3000);
import httpx
 
exposed = sandbox.expose_port(3000)
print(exposed.url)  # open in a browser; it carries the token
httpx.get(f"https://{exposed.hostname}/api", headers={"X-Lizard-Access-Token": exposed.access_token})
sandbox.unexpose(3000)

Pausa, snapshot y fork

Estas llamadas conservan la memoria y los procesos en ejecución, no solo los archivos. El inicio rápido explica qué conserva cada una, cómo se facturan los restores y qué puede fallar.

await sandbox.pause();
await sandbox.waitForStatus('paused');
await sandbox.resume();
await sandbox.waitForStatus('running');
 
const saved = await sandbox.snapshot('ready-env');
const copy = await Sandbox.restore(saved.id);
 
for (const f of await sandbox.fork({ count: 2 })) {
  if (f.sandbox) await f.sandbox.process.exec('echo hi');
  else console.warn('fork failed:', f.error);
}
sandbox.pause()
sandbox.wait_for_status("paused")
sandbox.resume()
sandbox.wait_for_status("running")
 
saved = sandbox.snapshot("ready-env")
copy = Sandbox.restore(saved["id"])
 
for f in sandbox.fork(count=2):
    if f.sandbox:
        f.sandbox.process.exec_("echo hi")
    else:
        print("fork failed:", f.error)

fork devuelve una entrada por copia: el sandbox nuevo o un error, como el límite de sandboxes de la cuenta. Cada copia se factura como su origen.

Ejecutar código con estado

CodeSandbox arranca la plantilla interpreter y ejecuta código con runCode (Python: run_code). En esa plantilla, Python se ejecuta en un kernel de Jupyter persistente por contexto, así que las variables se conservan entre llamadas y los resultados pueden incluir gráficos como image/png. JavaScript y bash se ejecutan como un proceso nuevo en cada llamada. Consulta intérprete de código.

Volúmenes

Adjunta un volumen de Persistent Volumes por su nombre para conservar /workspace entre sandboxes:

import { Sandbox, Volume } from '@lizard-build/sdk';
 
await Volume.getOrCreate('proj_123', 'agent-workdir', { sizeGb: 10 });
const sandbox = await Sandbox.create('base', { projectId: 'proj_123', volumeName: 'agent-workdir' });
from lizard import Sandbox, Volume
 
Volume.get_or_create("proj_123", "agent-workdir", size_gb=10)
sandbox = Sandbox.create("base", project_id="proj_123", volume_name="agent-workdir")

API no compatibles

La vigilancia de archivos aún no está disponible. sandbox.fork() devuelve 409 cuando hay un volumen adjunto y 501 en un sandbox que se ejecuta como pod. Sandbox.connect no reanuda un sandbox pausado ni uno detenido; para uno pausado, llama a resume(). No hay acceso por el protocolo SSH; lizard sandbox ssh abre una shell interactiva con tus credenciales de la CLI.

Errores

Los fallos de la API lanzan (Python: raise) estos errores. Cada uno incluye el estado HTTP y, cuando la API lo envía, un code.

ErrorSignificado
PaymentRequiredErrorHTTP 402: la cuenta debe empezar Pro o pagar una factura antes de poder crear nada. url es la página que hay que abrir.
AuthenticationErrorHTTP 401 o 403: clave no válida o sin acceso.
NotFoundErrorHTTP 404: el sandbox, el archivo o el snapshot no existe o ha vencido.
ConflictErrorHTTP 409: estado en conflicto, como hacer fork de un sandbox con volumen.
TimeoutErrorHTTP 408 o 504.
LizardErrorOtros fallos de la API, incluidas las operaciones no compatibles.

Demasiados sandboxes a la vez, o demasiados inicios, devuelven HTTP 429; consulta límites de la cuenta.

API HTTP

El SDK llama a la API REST de Lizard en https://lizard.build. Envía tu clave API como Authorization: Bearer liz_... o en la cabecera X-API-Key.

LlamadaSolicitud
CrearPOST /api/sandboxes con template, projectId, size, timeoutMs, envs, metadata, region, volumeName; devuelve 201 con sandboxId
Obtener el estadoGET /api/sandboxes/{id}
ListarGET /api/sandboxes, o GET /api/projects/{projectId}/sandboxes para un proyecto
Ejecutar un comandoPOST /api/sandboxes/{id}/exec con cmd, envs, workdir, user, timeoutMs; devuelve stdout, stderr, exitCode
Cambiar la duraciónPOST /api/sandboxes/{id}/timeout con timeoutMs
Pausar o reanudarPOST /api/sandboxes/{id}/pause, POST /api/sandboxes/{id}/resume
Publicar un puertoPOST /api/sandboxes/{id}/expose/{port}; DELETE en la misma ruta lo retira
DetenerDELETE /api/sandboxes/{id}
curl -X POST https://lizard.build/api/sandboxes \
  -H "Authorization: Bearer $LIZARD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"template": "base", "projectId": "proj_123", "timeoutMs": 300000}'

La API directa crea un sandbox sin caducidad salvo que pases timeoutMs.

Almacenamiento y facturación

La facturación, el tráfico saliente y lo que sobrevive a una detención se describen en un solo lugar, en almacenamiento y facturación. Los tamaños y precios por hora están en límites.

Actualizado