Saltar a contenido

Novedades de 0.6.0

Publicada el 2026-10-03: SDK Python rayito 0.6.0, SDK TypeScript rayito 0.6.0 y rayd 0.6.0.

0.6.0 trae seis funciones nuevas y un convenio único para desplegar su infraestructura en tu cuenta. Todas están apagadas por defecto: sin la opción correspondiente, un sandbox se comporta byte a byte como en 0.5.x y el SDK no hace ninguna llamada nueva a AWS (una traza de oro en los tests de cada SDK lo comprueba).

Actualiza a 0.6.1

0.6.1 corrige que redesplegar una pila opcional devolviera sus parámetros a los valores por defecto y que reincarnate() perdiera mounts=, events= y telemetry=: Novedades de 0.6.1.

De un vistazo

Función Python TypeScript Imagen Coste en reposo Guía
Montajes S3 mounts={"/mnt/x": S3Mount(...)} mounts: { "/mnt/x": new S3Mount({...}) } rayito-base-caps, rayd 0.6.0 $0 (sólo IAM) Montajes S3
Tamaños size="4gb" size: "4gb" una imagen por tamaño (rayito image publish --sizes) snapshot por imagen publicada Tamaños
Eventos y webhooks events=LifecycleEvents() events: new LifecycleEvents() cualquiera con rayd 0.6.0 ≈ $0,40/mes (pila events-webhooks) Eventos y webhooks
Exportación OTLP telemetry=TelemetryExport(...) telemetry: new TelemetryExport({...}) rayd 0.6.0; caps con OtlpAuth.execution_role() $0 (sólo IAM) Exportación OTLP
Templates declarativos Template.build(t, "nombre", bucket=...) Template.build(t, "nombre", { bucket }) se compone sobre rayito-base publicada snapshot por versión construida Templates
Pasarela de secretos gateways={"api": SecretGateway(...)} gateways: { api: new SecretGateway({...}) } cualquiera con rayd 0.6.0 $0 (lecturas de Secrets Manager por uso) Pasarela de secretos
Pilas opcionales OptionalStacks().deploy(...) new OptionalStacks().deploy(...) — el de cada componente Pilas opcionales

Todas aceptadas contra AWS real; cada guía cita sus mediciones en AWS_API_NOTES.md. Las cifras y permisos de cada una, en una sola tabla: Funciones opcionales y su coste.

Montajes S3

Un bucket (o un prefijo) como carpeta normal del sandbox, con Mountpoint for Amazon S3. create() no devuelve el sandbox hasta que cada montaje está mounted; si alguno falla, lo termina y lanza MountException (TypeScript: MountError) con un code cerrado.

from rayito import S3Mount, Sandbox

with Sandbox.create(
    "rayito-base-caps",
    execution_role_arn="arn:aws:iam::123456789012:role/rayito-sandbox-caps",
    mounts={"/mnt/data": S3Mount(bucket="amzn-s3-demo-bucket", prefix="team7/")},
) as sbx:
    print(sbx.commands.run("ls /mnt/data").stdout)
    print(sbx.mounts["/mnt/data"].state)  # "mounted"
import { S3Mount, Sandbox } from "rayito";

await using sbx = await Sandbox.create({
  template: "rayito-base-caps",
  executionRoleArn: "arn:aws:iam::123456789012:role/rayito-sandbox-caps",
  mounts: { "/mnt/data": new S3Mount({ bucket: "amzn-s3-demo-bucket", prefix: "team7/" }) },
});
console.log((await sbx.commands.run("ls /mnt/data")).stdout);
console.log((await sbx.mounts()).get("/mnt/data")?.state); // "mounted"

Necesita la política de la pila s3-mounts en el execution role y el bucket en el allowlist de la imagen (RAYITO_ALLOWED_MOUNT_BUCKETS).

Catálogo de tamaños

Cinco tamaños con nombre (512mb, 1gb, 2gb, 4gb, 8gb) que el SDK resuelve en el cliente, sin ningún RPC: size="4gb" lanza la imagen rayito-base-4gb. Un tamaño intermedio se redondea hacia arriba con un aviso. rayito image publish --sizes 512mb,4gb publica las imágenes de cada tamaño desde el mismo artefacto.

from rayito import Sandbox

with Sandbox.create(size="4gb") as sbx:
    info = sbx.get_info()
    print(info.size, info.baseline_memory_mib, info.baseline_cpu)  # 4gb 4096 8
import { Sandbox } from "rayito";

await using sbx = await Sandbox.create({ size: "4gb" });
const info = await sbx.getInfo();
console.log(info.size, info.baselineMemoryMib, info.baselineCpu); // 4gb 4096 8
rayito image publish --artifact rayito-image.zip --base-image-version 1 \
  --bucket amzn-s3-demo-bucket --sizes 512mb,4gb
rayito image sizes

Eventos de ciclo de vida y webhooks

rayd firma cada transición (created, paused, resumed, killed) y una pila en tu cuenta las guarda en DynamoDB y las entrega a tus webhooks con la firma de E2B: un receptor escrito para E2B las verifica sin cambios (cómo verificar la firma).

from rayito import LifecycleEvents, Sandbox

events = LifecycleEvents()  # la pila de `rayito events deploy`
with Sandbox.create(
    execution_role_arn="arn:aws:iam::123456789012:role/rayito-sandbox",
    logging="cloudwatch",
    events=events,
) as sbx:
    sbx.pause()
    sbx.resume()
for event in events.get_events(sandbox_id=sbx.sandbox_id, order="asc"):
    print(event.type)  # sandbox.lifecycle.created, .paused, .resumed, .killed
import { LifecycleEvents, Sandbox } from "rayito";

const events = new LifecycleEvents(); // la pila de `rayito events deploy`
const sbx = await Sandbox.create({
  executionRoleArn: "arn:aws:iam::123456789012:role/rayito-sandbox",
  logging: "cloudwatch",
  events,
});
await sbx.pause();
await sbx.resume();
await sbx.kill();
for (const event of await events.getEvents({ sandboxId: sbx.sandboxId, order: "asc" })) {
  console.log(event.kind); // created, paused, resumed, killed
}
rayito events deploy --artifact-bucket amzn-s3-demo-bucket --log-group-name /rayito/rayito-base
rayito events webhook add https://hooks.example.com/rayito --secret-name mi-webhook \
  --type sandbox.lifecycle.killed

Exportación OTLP desde rayd

rayd exporta 7 métricas de CPU, memoria y disco a CloudWatch por OTLP/HTTP cada interval_s (60 s por defecto), firmadas con SigV4 (el execution role) o con un token guardado en Secrets Manager. Unos $0,00002 por sandbox-hora.

from rayito import OtlpAuth, Sandbox, TelemetryExport

with Sandbox.create(
    "rayito-base-caps",
    execution_role_arn="arn:aws:iam::123456789012:role/rayito-sandbox-caps",
    telemetry=TelemetryExport(auth=OtlpAuth.execution_role()),
) as sbx:
    print(sbx.get_telemetry_status().exported)
import { OtlpAuth, Sandbox, TelemetryExport } from "rayito";

await using sbx = await Sandbox.create({
  template: "rayito-base-caps",
  executionRoleArn: "arn:aws:iam::123456789012:role/rayito-sandbox-caps",
  telemetry: new TelemetryExport({ auth: OtlpAuth.executionRole() }),
});
console.log((await sbx.getTelemetryStatus()).exported);

Templates declarativos

El DSL Template de E2B v2, compilado en tu proceso a un Dockerfile determinista sobre una imagen rayito-base publicada, y construido con Lambda MicroVMs. Sin plano de control propio. En el shim, Template y AsyncTemplate construyen de verdad con la firma de E2B.

from rayito import Sandbox, Template, wait_for_port

t = (
    Template()
    .from_base_image("rayito-base")
    .pip_install(["pandas==2.2.3"])
    .set_start_cmd("python3 -m http.server 8000", wait_for_port(8000))
)
info = Template.build(t, "mi-api", bucket="amzn-s3-demo-bucket")
with Sandbox.create(info.template_id) as sbx:
    print(sbx.commands.run("curl -s localhost:8000").exit_code)
import { Sandbox, Template, waitForPort } from "rayito";

const t = new Template()
  .fromBaseImage("rayito-base")
  .pipInstall(["pandas==2.2.3"])
  .setStartCmd("python3 -m http.server 8000", waitForPort(8000));
const info = await Template.build(t, "mi-api", { bucket: "amzn-s3-demo-bucket" });
await using sbx = await Sandbox.create({ template: info.templateId });
console.log((await sbx.commands.run("curl -s localhost:8000")).exitCode);
rayito template build mi_template.py --name mi-api --bucket amzn-s3-demo-bucket
rayito template logs mi-api

Pasarela de secretos

El código del sandbox usa una credencial sin poder leerla: rayd abre una pasarela en loopback que comprueba una allowlist de método y ruta, inyecta la cabecera real (leída de Secrets Manager) y reenvía al upstream que declaraste. sbx.gateways.refresh() rota el secreto sin recrear el sandbox.

from rayito import Sandbox, SecretGateway

with Sandbox.create(
    gateways={
        "anthropic": SecretGateway(
            upstream="https://api.anthropic.com",
            headers={"x-api-key": "anthropic"},  # nombre del secreto, no su valor
            allow=[("POST", "/v1/messages")],
        )
    }
) as sbx:
    url = sbx.gateways["anthropic"].url  # http://127.0.0.1:<puerto>
    sbx.commands.run("python agent.py", envs={"ANTHROPIC_BASE_URL": url})
import { Sandbox, SecretGateway } from "rayito";

await using sbx = await Sandbox.create({
  gateways: {
    anthropic: new SecretGateway({
      upstream: "https://api.anthropic.com",
      headers: { "x-api-key": "anthropic" }, // nombre del secreto, no su valor
      allow: [["POST", "/v1/messages"]],
    }),
  },
});
const url = sbx.gateways.get("anthropic")?.url ?? "";
await sbx.commands.run("python agent.py", { envs: { ANTHROPIC_BASE_URL: url } });

Pilas opcionales y rayito stack

Cada función con infraestructura propia es un componente OptionalStack: una plantilla de CloudFormation que despliegas tú, con OptionalStacks.deploy/status/destroy o rayito stack. deploy imprime siempre el coste y pide confirmación; nada se despliega solo.

from rayito import OptionalStacks

stacks = OptionalStacks(region="us-east-1")
print([c.name for c in stacks.components() if c.supported])  # sin llamar a AWS
stacks.deploy("otlp-export")
import { OptionalStacks } from "rayito";

const stacks = new OptionalStacks({ region: "us-east-1" });
console.log(stacks.components().filter((c) => c.supported).map((c) => c.name));
await stacks.deploy("otlp-export");
rayito stack list
rayito stack deploy otlp-export
rayito stack status otlp-export

Por dentro: ConfigureSandbox

Las funciones que viven dentro del sandbox (mounts, events, telemetry y gateways) llegan a rayd por un único canal nuevo, ConfigureSandbox, justo después del primer Health y antes de que create() devuelva el sandbox. Si una sección falla, create() termina el MicroVM que acaba de lanzar (salvo keep_on_failure=True) y relanza el error: nunca recibes un sandbox a medio configurar. Contra una imagen con un rayd anterior a 0.6.0, esas opciones fallan con UnimplementedError. Diseño: ADR-015 y ADR-016 en ARCHITECTURE.md.

Cómo actualizar desde 0.5.x

  1. Actualiza el SDK (pip install -U "rayito[cli]" o pnpm add rayito@latest). Sin opciones nuevas, tu código sigue igual.
  2. Para usar mounts, events, telemetry, gateways o set_start_cmd() de los templates, republica tu imagen sobre rayd 0.6.x (Imágenes) y comprueba la compatibilidad con rayito doctor.
  3. Despliega sólo las pilas de las funciones que uses (rayito stack deploy <componente>).

No hay cambios incompatibles en la API pública de 0.5.x. Lo único que cambia para el shim de E2B: Template, AsyncTemplate, TemplateException y BuildException pasan de lanzar UnimplementedError a funcionar de verdad (Paridad con E2B).

Lo que no trae 0.6.0

Volúmenes EFS (volumes=) y dominio propio (domain=) seguían en desarrollo: sus opciones existían en la firma de create() y lanzaban UnimplementedError sin llamar a AWS. Los volúmenes EFS y CustomDomain (experimental) llegan en 0.7.0; domain= sigue en desarrollo.

Detalle completo: Changelog.