Saltar a contenido

Ejecutar código

run_code ejecuta una celda en un kernel Jupyter con estado dentro del sandbox, como un notebook: las variables, los imports y los ficheros abiertos siguen ahí en la siguiente llamada.

Cuándo usarlo

  • El caso típico de un agente: generar Python, ejecutarlo y leer el resultado, la salida o la traza del error.
  • Análisis de datos con pandas y gráficos con matplotlib: los gráficos vuelven como PNG y como datos estructurados.
  • Cuándo no: para procesos de sistema o servidores, usa comandos. Para bash, JavaScript o TypeScript, mira Lenguajes y kernels.

Ejemplo rápido

from rayito import Sandbox

with Sandbox.create() as sbx:
    sbx.run_code("x = 42")
    print(sbx.run_code("x").text)  # "42": el kernel tiene estado

    failed = sbx.run_code("1/0")
    print(failed.error.name if failed.error else None)  # "ZeroDivisionError" (1)
  1. Un error del código es un dato de la Execution, nunca una excepción de Python.
import asyncio

from rayito import AsyncSandbox


async def main() -> None:
    async with await AsyncSandbox.create() as sbx:
        await sbx.run_code("x = 42")
        print((await sbx.run_code("x")).text)  # "42"

        failed = await sbx.run_code("1/0")
        print(failed.error.name if failed.error else None)  # "ZeroDivisionError"


asyncio.run(main())
import { Sandbox } from "rayito";

await using sbx = await Sandbox.create();
await sbx.runCode("x = 42");
console.log((await sbx.runCode("x")).text); // "42"

const failed = await sbx.runCode("1/0");
console.log(failed.error?.name); // "ZeroDivisionError"

Paso a paso

Qué devuelve: Execution

Campo Qué es
text el text/plain del resultado principal (el valor de la última expresión), o None
results lista de Result, uno por cada salida rica (display(), gráficos, la última expresión)
logs.stdout, logs.stderr listas con lo que la celda imprimió
error ExecutionError(name, value, traceback) si la celda lanzó, o None
execution_count el contador del kernel

Cada Result trae las representaciones que produjo el kernel: text, html, markdown, svg, png, jpeg, pdf, latex, json, javascript, chart (datos del gráfico) y data. formats() dice cuáles hay, is_main_result (TypeScript: isMainResult) marca el valor de la última expresión y extra guarda los tipos MIME que no tienen campo propio (y el aviso rayito/omitted de un resultado demasiado grande).

Gráficos

import base64

from rayito import Sandbox

with Sandbox.create() as sbx:
    plot = sbx.run_code("import matplotlib.pyplot as plt; plt.plot([1, 2, 3]); plt.show()")
    chart = plot.results[0]
    print(chart.formats())  # incluye 'png' y 'chart'
    with open("grafico.png", "wb") as out:
        out.write(base64.b64decode(chart.png or ""))  # (1)!
  1. png llega en base64, como en Jupyter.
import asyncio
import base64

from rayito import AsyncSandbox


async def main() -> None:
    async with await AsyncSandbox.create() as sbx:
        plot = await sbx.run_code("import matplotlib.pyplot as plt; plt.plot([1, 2, 3]); plt.show()")
        chart = plot.results[0]
        print(chart.formats())  # incluye 'png' y 'chart'
        with open("grafico.png", "wb") as out:
            out.write(base64.b64decode(chart.png or ""))


asyncio.run(main())
import { writeFile } from "node:fs/promises";
import { Sandbox } from "rayito";

await using sbx = await Sandbox.create();
const plot = await sbx.runCode("import matplotlib.pyplot as plt; plt.plot([1, 2, 3]); plt.show()");
const chart = plot.results[0];
console.log(chart?.formats()); // incluye "png" y "chart"
await writeFile("grafico.png", Buffer.from(chart?.png ?? "", "base64"));

Salida en streaming

on_stdout, on_stderr, on_result y on_error reciben cada salida mientras la celda corre, sin esperar al final:

from rayito import Sandbox

with Sandbox.create() as sbx:
    sbx.run_code(
        "import time\nfor i in range(3):\n    print(i); time.sleep(1)",
        on_stdout=lambda message: print("stdout:", message.line, end=""),
    )
import asyncio

from rayito import AsyncSandbox


async def main() -> None:
    async with await AsyncSandbox.create() as sbx:
        await sbx.run_code(
            "import time\nfor i in range(3):\n    print(i); time.sleep(1)",
            on_stdout=lambda message: print("stdout:", message.line, end=""),
        )


asyncio.run(main())
import { Sandbox } from "rayito";

await using sbx = await Sandbox.create();
await sbx.runCode("import time\nfor i in range(3):\n    print(i); time.sleep(1)", {
  onStdout: (message) => process.stdout.write(`stdout: ${message.line}`),
});

Contextos

Cada contexto es un kernel independiente con su propio estado. El contexto default existe siempre; create_code_context() crea otros (con un tope por sandbox, ver Límites), con su cwd, su language, sus envs y, opcionalmente, sus secrets. Devuelve un CodeContext (id, language, cwd); run_code(context=), restart_code_context() y remove_code_context() aceptan el objeto o su id.

from rayito import Sandbox

with Sandbox.create() as sbx:
    sbx.run_code("x = 1")
    ctx = sbx.create_code_context(cwd="/tmp")
    print(sbx.run_code("x", context=ctx).error)  # NameError: otro kernel
    print([c.id for c in sbx.list_code_contexts()])  # ['default', 'ctx-…']
    sbx.restart_code_context(ctx)  # vacía su estado
    sbx.remove_code_context(ctx)
import asyncio

from rayito import AsyncSandbox


async def main() -> None:
    async with await AsyncSandbox.create() as sbx:
        await sbx.run_code("x = 1")
        ctx = await sbx.create_code_context(cwd="/tmp")
        print((await sbx.run_code("x", context=ctx)).error)  # NameError
        await sbx.remove_code_context(ctx)


asyncio.run(main())
import { Sandbox } from "rayito";

await using sbx = await Sandbox.create();
await sbx.runCode("x = 1");
const ctx = await sbx.createCodeContext({ cwd: "/tmp" });
console.log((await sbx.runCode("x", { context: ctx })).error?.name); // "NameError"
console.log((await sbx.listCodeContexts()).map((c) => c.id));
await sbx.restartCodeContext(ctx);
await sbx.removeCodeContext(ctx);

Timeouts

timeout (300 s por defecto) lo impone el agente: al vencer interrumpe el kernel y la Execution vuelve con error.name == "ExecutionTimeout". El kernel sigue utilizable en la siguiente celda; si no se recupera en 5 s, el agente reinicia ese contexto (y su estado se pierde).

Opciones de run_code

Python TypeScript Por defecto Qué hace
code code — el código de la celda
language language "python" bash, javascript/js, typescript/ts en rayito-base-poly (Kernels)
context context default contexto (objeto o id); excluyente con language
on_stdout, on_stderr onStdout, onStderr — cada línea impresa, como OutputMessage
on_result, on_error onResult, onError — cada Result y el error
envs envs — variables de entorno sólo durante esta celda (contextos Python)
timeout timeoutMs 300 s / 300 000 ms límite del agente; None / 0 sin límite
request_timeout requestTimeoutMs 60 s plazo de la llamada
secrets secrets — secretos en el entorno de la celda (opcional, con coste)

Errores y solución de problemas

Situación Python TypeScript Qué hacer
el código lanza execution.error (no es una excepción) execution.error lee error.name, error.value y error.traceback
la celda tarda más que timeout error.name == "ExecutionTimeout" igual sube timeout
language y context a la vez, envs en un kernel no Python, code de más de 1 MiB InvalidArgumentException InvalidArgumentError elige uno; para código grande, escríbelo a un fichero y ejecútalo
kernel que la imagen no trae (bash en rayito-base) UnimplementedError UnimplementedError usa rayito-base-poly
demasiados contextos (Límites) RateLimitException RateLimitError borra contextos con remove_code_context
una celda silenciosa se suspende a mitad (el SDK se reengancha solo) igual sube max_idle_seconds (Pausar y reanudar)

Diferencias con E2B

  • La misma API: rayito.e2b (Python y TypeScript) llama al run_code nativo y devuelve la misma Execution. Dos detalles del shim: un language que no existe (r, java) es UnimplementedError sin llamar al agente, como en E2B, y en Python timeout=None son los 300 s por defecto (en el nativo, None es sin límite). En el shim de Python, secrets= y los envs de create_code_context sólo están en el nativo (sbx.native).
  • Lenguajes: Python siempre; bash, JavaScript y TypeScript en rayito-base-poly; R y Java no existen.

Ver también