Subclients¶
The objects that hang off a sandbox (sbx.commands, sbx.files,
sbx.pty, sbx.git, sbx.agent), their handles and the paginator of
Sandbox.paginate(). The async variants (AsyncCommandHandle,
AsyncWatchHandle, AsyncUploadTicket, AsyncPtyHandle, AsyncGit,
AsyncAgentStream, AsyncSandboxListPaginator) have the same surface
with coroutines.
Commands¶
Commands(sandbox: Sandbox)
¶
Comandos del sandbox (ProcessService).
run(cmd: str, *, background: bool = False, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, on_stdout: OutputCallback | None = None, on_stderr: OutputCallback | None = None, stdin: bool = False, timeout: float | None = DEFAULT_COMMAND_TIMEOUT_SECONDS, request_timeout: float | None = None, tag: str | None = None, secrets: Mapping[str, str | SecretRef] | None = None, max_output_bytes: int = COMMAND_OUTPUT_MAX_BYTES, kill_tree: bool = False) -> CommandResult | CommandHandle
¶
run(
cmd: str,
*,
background: Literal[False] = False,
envs: Mapping[str, str] | None = None,
user: str | None = None,
cwd: str | None = None,
on_stdout: OutputCallback | None = None,
on_stderr: OutputCallback | None = None,
stdin: bool = False,
timeout: float | None = DEFAULT_COMMAND_TIMEOUT_SECONDS,
request_timeout: float | None = None,
tag: str | None = None,
secrets: Mapping[str, str | SecretRef] | None = None,
max_output_bytes: int = COMMAND_OUTPUT_MAX_BYTES,
kill_tree: bool = False,
) -> CommandResult
run(
cmd: str,
*,
background: Literal[True],
envs: Mapping[str, str] | None = None,
user: str | None = None,
cwd: str | None = None,
on_stdout: OutputCallback | None = None,
on_stderr: OutputCallback | None = None,
stdin: bool = False,
timeout: float | None = DEFAULT_COMMAND_TIMEOUT_SECONDS,
request_timeout: float | None = None,
tag: str | None = None,
secrets: Mapping[str, str | SecretRef] | None = None,
max_output_bytes: int = COMMAND_OUTPUT_MAX_BYTES,
kill_tree: bool = False,
) -> CommandHandle
run(
cmd: str,
*,
background: bool,
envs: Mapping[str, str] | None = None,
user: str | None = None,
cwd: str | None = None,
on_stdout: OutputCallback | None = None,
on_stderr: OutputCallback | None = None,
stdin: bool = False,
timeout: float | None = DEFAULT_COMMAND_TIMEOUT_SECONDS,
request_timeout: float | None = None,
tag: str | None = None,
secrets: Mapping[str, str | SecretRef] | None = None,
max_output_bytes: int = COMMAND_OUTPUT_MAX_BYTES,
kill_tree: bool = False,
) -> CommandResult | CommandHandle
Ejecuta cmd con /bin/bash -l -c como user (uid 1000 por defecto).
timeout lo impone el agente sobre el reloj corrido (SIGTERM al
vencer, SIGKILL 5 s después; una pausa no lo consume) y por defecto
son 60 s; None o 0 lo desactivan. En foreground el resultado
llega con la salida y un exit distinto de cero es
CommandExitException; el timeout es TimeoutException. La salida
guardada (la del resultado y la del handle) está acotada a
max_output_bytes por descriptor (64 MiB por defecto): lo más
antiguo se descarta y truncated lo indica; 0 no guarda nada.
on_stdout/on_stderr reciben siempre todo. En background
devuelve un CommandHandle que consume el stream cuando se itera o se
llama a wait(): mientras nadie lo lee, el agente aplica backpressure
y, tras 30 s con el canal lleno, cierra ese suscriptor con
output_truncated. Un stream abierto cuenta como actividad para la
política de idle del MicroVM. request_timeout acota los unarios que
el handle haga después (kill, send_stdin, close_stdin).
kill_tree=True hace que el timeout y kill() alcancen también a los
descendientes que salieron del grupo del proceso (setsid, un doble
fork): el agente lo hace child subreaper de ellos, manda el SIGTERM
del timeout a todo el árbol y, tras la gracia, congela y mata a los
que queden; el fin del comando llega cuando ya no queda ninguno. Con
False (por defecto) sólo se señala el grupo, como en E2B. Lo que el
comando deja vivo al terminar por sí mismo no se toca.
Coste y activación¶
Activa: secrets={"ENV": "nombre" | SecretRef} inyecta secretos de
Secrets Manager como variables de entorno de este comando (más los
del handle; una clave que también esté en envs es
InvalidArgumentException).
Recursos y llamadas AWS: secretsmanager:GetSecretValue sólo en un
fallo de SecretCache (TTL 300 s): tres comandos seguidos = una
lectura. Ningún recurso nuevo.
Coste aproximado: $0,05 por 10 000 llamadas (us-east-1, 2026-09-30).
IAM: secretsmanager:GetSecretValue en las credenciales del llamante.
Cómo apagarla: secrets=None (por defecto).
Ejemplo:
sbx.commands.run("python agent.py", secrets={"OPENAI_API_KEY": "openai"})
Con tracer_provider= en create()/connect(), cada llamada abre un
span rayito.commands.run (nunca con el texto del comando, sus
argumentos ni sus envs): rayito.commands.background siempre, y en
foreground rayito.commands.exit_code al terminar (también cuando sale con
un código distinto de cero). En segundo plano
el span se cierra en cuanto start devuelve el handle, no cuando el
proceso termina.
connect(pid: int, *, from_seq: int = 0, on_stdout: OutputCallback | None = None, on_stderr: OutputCallback | None = None, timeout: float | None = None, request_timeout: float | None = None, max_output_bytes: int = COMMAND_OUTPUT_MAX_BYTES) -> CommandHandle
¶
Se engancha a un proceso vivo o terminado hace menos de 30 s.
from_seq=0 entrega sólo salida nueva; N reenvía primero lo retenido
con seq >= N (último MiB). Un seq ya descartado o un pid
desconocido es NotFoundException. timeout es aquí el deadline gRPC
del stream (no hay timeout de servidor en Connect). max_output_bytes
acota la salida guardada como en run.
list(*, request_timeout: float | None = None) -> list[ProcessInfo]
¶
Procesos y PTY vivos (los terminados desaparecen aunque sigan conectables).
kill(pid: int, *, request_timeout: float | None = None) -> bool
¶
SIGKILL al grupo del proceso (o de la PTY) y, si se lanzó con
kill_tree=True, antes a todo su árbol. False si el pid no existe o
ya terminó.
send_stdin(pid: int, data: str | bytes, *, request_timeout: float | None = None) -> None
¶
Escribe en el stdin de un proceso lanzado con stdin=True (str va
en UTF-8). Un pid de PTY es InvalidArgumentException: usa pty.send_input.
close_stdin(pid: int, *, request_timeout: float | None = None) -> None
¶
EOF en el stdin del proceso; idempotente.
CommandHandle(*, commands: Commands, call: Any, progress: CommandProgress, request_timeout: float | None, deadline_at: float | None = None, foreground: bool = False)
¶
Un proceso en background o enganchado con connect.
Consume el stream perezosamente en el hilo que itera o llama a wait();
disconnect() cancela el stream sin tocar el proceso, que sigue vivo y
listado hasta que termine o alguien lo mate. Si el agente cierra el
stream por un /suspend o el proxy lo corta, la siguiente lectura espera
al agente y se reengancha con Connect(pid, from_seq=last_seq + 1);
reconnects cuenta esas veces. Leer un handle en background nunca
despierta un sandbox suspendido: la lectura se bloquea (sin consumir
reconnect_timeout) hasta el resume(), el auto-resume que provoque
otra llamada o el fin del MicroVM.
last_seq: int
property
¶
Último seq recibido; connect(pid, from_seq=last_seq + 1) reanuda sin huecos.
reconnects: int
property
¶
Veces que el handle se reenganchó tras un suspend/resume o un corte.
wait(on_pty: Callable[[bytes], Any] | None = None, on_stdout: Callable[[str], Any] | None = None, on_stderr: Callable[[str], Any] | None = None) -> CommandResult
¶
Consume el stream hasta el EndEvent. Exit distinto de cero →
CommandExitException; timeout del agente → TimeoutException;
output_truncated → SandboxException. Idempotente.
on_stdout/on_stderr (texto) y on_pty (bytes de una PTY) reciben
cada chunk que esta llamada consume, después de los callbacks de
run(); lo ya leído antes (iterando) no se repite.
disconnect() -> None
¶
Cancela el stream; el proceso sigue corriendo en el sandbox. Un handle desconectado nunca reconecta.
AsyncCommandHandle(*, commands: AsyncCommands, call: Any, progress: CommandProgress, request_timeout: float | None, deadline_at: float | None = None, foreground: bool = False)
¶
CommandHandle sobre grpc.aio: await wait(), async for y
await kill()/send_stdin()/close_stdin(); disconnect() es síncrono.
Reconecta como CommandHandle tras un suspend/resume.
wait(on_pty: Callable[[bytes], Any] | None = None, on_stdout: Callable[[str], Any] | None = None, on_stderr: Callable[[str], Any] | None = None) -> CommandResult
async
¶
Como CommandHandle.wait; los callbacks pueden ser síncronos o
async (su resultado se espera si es awaitable antes del siguiente
chunk).
Files¶
Filesystem(sandbox: Sandbox)
¶
Ficheros del sandbox (FilesystemService).
read(path: str, *, format: str = 'text', gzip: bool = False, stream_idle_timeout: float | None = None, user: str | None = None, request_timeout: float | None = None) -> str | bytes | Iterator[bytes]
¶
read(
path: str,
*,
format: Literal["text"] = "text",
gzip: bool = False,
stream_idle_timeout: float | None = None,
user: str | None = None,
request_timeout: float | None = None,
) -> str
Lee un fichero regular: text (UTF-8 estricto), bytes o stream
(chunks de hasta 256 KiB tal como llegan). Hace Stat primero: un
directorio o un symlink es InvalidArgumentException sin abrir el
stream, y el deadline del Read es 60 s + 1 s por MB del tamaño
salvo request_timeout.
gzip=True pide la respuesta comprimida (inocuo en una imagen
anterior, que responde sin comprimir). stream_idle_timeout (s)
cancela la lectura si el siguiente chunk tarda más y levanta
TimeoutException. Con transfer=S3Staging(...) un fichero de al
menos threshold_bytes se exporta a S3 y se descarga con tus
credenciales (verificando su sha256); gzip no aplica ahí.
Con tracer_provider= abre rayito.files.read (nunca con path ni
el contenido como atributo); en format="text"/"bytes",
rayito.files.bytes al terminar.
write(path: str, data: str | bytes | IO[bytes] | IO[str], *, user: str | None = None, mode: int | None = None, gzip: bool = False, metadata: Mapping[str, str] | None = None, use_octet_stream: bool = False, request_timeout: float | None = None) -> EntryInfo
¶
Escribe data (str en UTF-8, bytes o fichero abierto) de forma
atómica, creando los padres y con mode (0o644 por defecto). Los
padres que falten se crean; el propietario es user. gzip,
metadata y use_octet_stream como en write_files.
Con tracer_provider= abre rayito.files.write (nunca con path ni
data), con rayito.files.bytes al terminar.
write_files(files: Sequence[WriteEntry], *, user: str | None = None, gzip: bool = False, metadata: Mapping[str, str] | None = None, use_octet_stream: bool = False, request_timeout: float | None = None) -> list[EntryInfo]
¶
N ficheros en un stream Write; devuelve sus EntryInfo en
orden. Cada fichero se compromete de forma atómica por separado: si
el stream falla a mitad, los ya escritos quedan y el resto no existe.
Deadline 60 s + 1 s por MB del total salvo request_timeout.
gzip=True comprime el stream (grpc-encoding: gzip). metadata
(claves token de HTTP, se guardan en minúsculas) se aplica a cada
fichero y sustituye el conjunto entero; se valida antes de cualquier
RPC. Ambos exigen un agente 0.3.0 o posterior (UnimplementedError si no).
use_octet_stream se acepta y no tiene efecto (gRPC no usa
formularios). Con transfer=S3Staging(...), cada fichero de al menos
threshold_bytes (o un stream binario no buscable) se sube a S3 con
tus credenciales y rayd lo importa; gzip no aplica ahí.
Con tracer_provider= abre rayito.files.write_files (nunca las
rutas ni los datos), con rayito.files.count y rayito.files.bytes
al terminar.
upload_url(path: str, *, user: str | None = None, expires_in: int = TRANSFER_DEFAULT_EXPIRES_IN_SECONDS, max_bytes: int | None = None, form: bool = False, request_timeout: float | None = None) -> UploadTicket
¶
Una URL de subida a S3 firmada con tus credenciales, con la
importación a path ya armada en el sandbox. Es un str:
requests.put(ticket, data=f, headers=ticket.headers) basta; con
form=True es un formulario POST (ticket.fields más el fichero en
file) que S3 limita a max_bytes. De un solo uso; expires_in se
topa en min(expires_in, transfer.max_expires_in, 604800). El
fichero aparece de forma asíncrona: read, get_info, list, un
comando o una celda esperan a la importación, y ticket.wait() la
espera explícitamente. Sin transfer=S3Staging(...) ni
RAYITO_TRANSFER_BUCKET levanta UnimplementedError.
download_url(path: str, *, user: str | None = None, expires_in: int = TRANSFER_DEFAULT_EXPIRES_IN_SECONDS, filename: str | None = None, request_timeout: float | None = None) -> DownloadLink
¶
Exporta path tal como está ahora a S3 y devuelve una URL de
descarga firmada con tus credenciales (un str con size, sha256
y expires_at); urlopen(link) basta y admite Range. Un fichero
inexistente levanta FileNotFoundException al llamar; un directorio
o un symlink, InvalidArgumentException. filename es el nombre de
Content-Disposition (por defecto el de path).
list(path: str, *, depth: int = 1, user: str | None = None, request_timeout: float | None = None) -> list[EntryInfo]
¶
Entradas hasta depth niveles (1 = sólo hijos directos; 0 vale 1)
en preorden, ordenadas por nombre en cada directorio, sin seguir
symlinks. Más de 10 000 entradas es RateLimitException.
Con tracer_provider= abre rayito.files.list (nunca path), con
rayito.files.count al terminar.
exists(path: str, *, user: str | None = None, request_timeout: float | None = None) -> bool
¶
False sólo si Stat responde NOT_FOUND; otros errores se propagan.
Con tracer_provider= abre rayito.files.exists (nunca path).
get_info(path: str, *, user: str | None = None, request_timeout: float | None = None) -> EntryInfo
¶
Stat sin seguir symlinks (type is FileType.SYMLINK con symlink_target).
Con tracer_provider= abre rayito.files.get_info (nunca path).
remove(path: str, *, recursive: bool = True, user: str | None = None, request_timeout: float | None = None) -> None
¶
Borra un fichero, symlink (sólo el enlace) o directorio; con
recursive=False un directorio no vacío es InvalidArgumentException.
Con tracer_provider= abre rayito.files.remove (nunca path).
rename(old_path: str, new_path: str, *, user: str | None = None, request_timeout: float | None = None) -> EntryInfo
¶
rename(2): reemplaza un fichero regular existente; un destino que
es un directorio no vacío es InvalidArgumentException.
Con tracer_provider= abre rayito.files.rename (nunca las rutas).
make_dir(path: str, *, user: str | None = None, request_timeout: float | None = None) -> bool
¶
Crea el directorio y sus padres (0o755). True si lo creó, False si
ya existía; si existe algo que no es un directorio,
InvalidArgumentException.
Con tracer_provider= abre rayito.files.make_dir (nunca path).
watch_dir(path: str, *, on_event: EventCallback | None = None, on_exit: ExitCallback | None = None, recursive: bool = False, include_entry: bool = False, user: str | None = None, timeout: float | None = 0, request_timeout: float | None = None) -> WatchHandle
¶
Observa un directorio (inotify, sin debounce). Bloquea hasta
WatchStarted y devuelve un WatchHandle que consume el stream en
un hilo daemon: con on_event cada evento va al callback; sin él se
acumulan para get_new_events(). timeout (> 0) es el deadline gRPC
del stream y termina en TimeoutException; 0/None es ilimitado.
request_timeout se acepta por uniformidad y no aplica al stream. Un
files.write en el directorio aparece como un único WRITE.
WatchHandle(*, filesystem: Filesystem, call: Any, path: str, state: WatchState, on_exit: ExitCallback | None, request: filesystem_pb2.WatchDirRequest | None = None, deadline_at: float | None = None)
¶
Un watch_dir vivo. stop() cancela el stream, espera al hilo (≤ 5 s)
y es idempotente; Sandbox.close() lo llama por cada handle vivo. Tras
un suspend/resume (o un corte del proxy) el hilo consumidor espera al
agente y vuelve a emitir WatchDir sin llamar a on_exit; reconnects
cuenta esas veces.
AsyncWatchHandle(*, filesystem: AsyncFilesystem, call: Any, path: str, state: WatchState, on_exit: ExitCallback | None, request: filesystem_pb2.WatchDirRequest | None = None, deadline_at: float | None = None)
¶
WatchHandle sobre grpc.aio: await get_new_events(), await stop()
y async with.
UploadTicket
¶
Bases: UploadTicketBase
Resultado de files.upload_url: la importación ya está armada en
rayd antes de que la URL exista para el caller, y es de un solo uso.
wait() sigue la transferencia hasta su final y devuelve el EntryInfo
escrito (o levanta la excepción mapeada); con timeout agotado levanta
TimeoutException y el ticket sigue armado. status() es una foto y
cancel() la cancela (idempotente).
AsyncUploadTicket
¶
Bases: UploadTicketBase
UploadTicket de AsyncSandbox: wait(), status() y cancel()
son corrutinas.
Terminal (PTY)¶
Pty(sandbox: Sandbox)
¶
Terminales interactivas del sandbox (PtyService).
create(*, size: PtySize | None = None, user: str | None = None, cwd: str | None = None, envs: Mapping[str, str] | None = None, shell: str | None = None, on_data: PtyDataCallback | None = None, timeout: float | None = DEFAULT_PTY_TIMEOUT_SECONDS, request_timeout: float | None = None, secrets: Mapping[str, str | SecretRef] | None = None) -> PtyHandle
¶
Abre una terminal con el shell de login de user (uid 1000 por
defecto) como <shell> -i -l, TERM=xterm-256color y LANG/
LC_ALL=C.UTF-8 (los envs del request ganan). size es 80x24 si
se omite; shell debe ser una ruta absoluta.
timeout (60 s por defecto, como en E2B) lo impone el agente sobre el
reloj corrido: al vencer manda SIGTERM al grupo y wait() termina en
TimeoutException. Para un shell que deba sobrevivir, timeout=None.
on_data recibe cada chunk de bytes de la terminal mientras el
handle se itera o se espera; el SDK nunca los loguea.
Coste y activación¶
Activa: secrets= inyecta secretos como variables de entorno del shell
(más los del handle).
Recursos y llamadas AWS: secretsmanager:GetSecretValue sólo en un
fallo de SecretCache (TTL 300 s).
Coste aproximado: $0,05 por 10 000 llamadas (us-east-1, 2026-09-30).
IAM: secretsmanager:GetSecretValue en las credenciales del llamante.
Cómo apagarla: secrets=None (por defecto).
Ejemplo:
term = sbx.pty.create(secrets={"GITHUB_TOKEN": "gh"})
connect(pid: int, *, from_seq: int = 0, on_data: PtyDataCallback | None = None, timeout: float | None = None, request_timeout: float | None = None) -> PtyHandle
¶
Se reengancha a una PTY viva o terminada hace menos de 30 s.
from_seq=0 entrega sólo salida nueva; N reenvía lo retenido con
seq >= N. timeout es el deadline gRPC de este stream.
send_input(pid: int, data: str | bytes, *, request_timeout: float | None = None) -> None
¶
Escribe en la terminal (str va en UTF-8; un \n final ejecuta la
línea). Una PTY terminada es NotFoundException; el pid de un proceso
normal es InvalidArgumentException.
resize(pid: int, size: PtySize, *, request_timeout: float | None = None) -> None
¶
TIOCSWINSZ sobre la terminal; el shell recibe SIGWINCH.
kill(pid: int, *, request_timeout: float | None = None) -> bool
¶
SIGKILL al grupo de la terminal. False si el pid no existe o ya terminó.
PtyHandle(*, pty: Pty, call: Any, progress: CommandProgress, request_timeout: float | None, deadline_at: float | None = None)
¶
Bases: CommandHandle
Una terminal abierta con pty.create o pty.connect.
Es un CommandHandle (pid, last_seq, stdout con la salida de la
terminal decodificada, stderr vacío, exit_code, error, wait(),
disconnect(), reconnects) cuya iteración entrega (None, None, bytes)
por mensaje y cuyo kill() es PtyService.Kill. send_input escribe en
la terminal y resize cambia su tamaño.
AsyncPtyHandle(*, pty: AsyncPty, call: Any, progress: CommandProgress, request_timeout: float | None, deadline_at: float | None = None)
¶
Git¶
Git(commands: Commands)
¶
Operaciones git en el sandbox con la superficie de E2B 2.51
(sandbox.git). E2B marca su módulo como obsoleto a favor de
commands.run(); aquí se mantiene por paridad.
timeout=None (por defecto) es sin plazo de servidor. Un fallo de
autenticación contra un remoto es GitAuthException, un push/pull sin
upstream GitUpstreamException y cualquier otro fallo el
CommandExitException del comando, sin la contraseña cuando la llamada
llevaba credenciales.
clone(url: str, path: str | None = None, branch: str | None = None, depth: int | None = None, username: str | None = None, password: str | None = None, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None, dangerously_store_credentials: bool = False) -> CommandResult
¶
git clone. Con username y password clona desde la URL con
las credenciales y, salvo dangerously_store_credentials=True,
deja origin apuntando a la URL sin ellas.
remote_add(path: str, name: str, url: str, fetch: bool = False, overwrite: bool = False, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> CommandResult
¶
git remote add [-f]; con overwrite cae a remote set-url si
el remoto ya existe.
remote_get(path: str, name: str, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> str | None
¶
La URL del remoto, o None si no existe.
add(path: str, files: Sequence[str] | None = None, all: bool = True, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> CommandResult
¶
git add -- <files>; sin files, -A (o . con all=False).
reset(path: str, mode: GitResetMode | None = None, target: str | None = None, paths: Sequence[str] | None = None, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> CommandResult
¶
Un mode fuera de soft/mixed/hard/merge/keep es
InvalidArgumentException sin ejecutar nada.
restore(path: str, paths: Sequence[str], staged: bool | None = None, worktree: bool | None = None, source: str | None = None, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> CommandResult
¶
Sin staged ni worktree restaura el árbol de trabajo;
staged=True solo saca del índice. Una lista vacía es
InvalidArgumentException sin ejecutar nada.
push(path: str, remote: str | None = None, branch: str | None = None, set_upstream: bool = True, username: str | None = None, password: str | None = None, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> CommandResult
¶
git push. Con credenciales: remote get-url, remote set-url
con la URL con credenciales, el push y, pase lo que pase, remote
set-url con la URL original.
pull(path: str, remote: str | None = None, branch: str | None = None, username: str | None = None, password: str | None = None, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> CommandResult
¶
git pull. Sin remote ni branch exige una rama con upstream
(GitUpstreamException si no la hay); las credenciales se inyectan y
se retiran como en push.
set_config(key: str, value: str, scope: str = 'global', path: str | None = None, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> CommandResult
¶
git config --global|--local|--system; scope="local" necesita path.
get_config(key: str, scope: str = 'global', path: str | None = None, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> str | None
¶
El valor, o None si la clave no está en ese scope.
dangerously_authenticate(username: str, password: str, host: str = 'github.com', protocol: str = 'https', envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> CommandResult
¶
Autentica git para todo el sandbox con el helper store:
credential.helper=store global y git credential approve.
Las credenciales quedan en ~/.git-credentials del usuario del
sandbox y son visibles para cualquier código que corra en él, igual
que en E2B. Usa tokens de vida corta. El SDK nunca las loguea.
configure_user(name: str, email: str, scope: str = 'global', path: str | None = None, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> CommandResult
¶
user.name y user.email en el scope pedido.
AsyncGit(commands: AsyncCommands)
¶
Git como corrutinas (la clase Git del SDK async de E2B 2.51). E2B
marca su módulo como obsoleto a favor de commands.run(); aquí se
mantiene por paridad.
timeout=None (por defecto) es sin plazo de servidor. Un fallo de
autenticación contra un remoto es GitAuthException, un push/pull sin
upstream GitUpstreamException y cualquier otro fallo el
CommandExitException del comando, sin la contraseña cuando la llamada
llevaba credenciales.
clone(url: str, path: str | None = None, branch: str | None = None, depth: int | None = None, username: str | None = None, password: str | None = None, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None, dangerously_store_credentials: bool = False) -> CommandResult
async
¶
git clone. Con username y password clona desde la URL con
las credenciales y, salvo dangerously_store_credentials=True,
deja origin apuntando a la URL sin ellas.
remote_add(path: str, name: str, url: str, fetch: bool = False, overwrite: bool = False, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> CommandResult
async
¶
git remote add [-f]; con overwrite cae a remote set-url si
el remoto ya existe.
remote_get(path: str, name: str, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> str | None
async
¶
La URL del remoto, o None si no existe.
add(path: str, files: Sequence[str] | None = None, all: bool = True, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> CommandResult
async
¶
git add -- <files>; sin files, -A (o . con all=False).
reset(path: str, mode: GitResetMode | None = None, target: str | None = None, paths: Sequence[str] | None = None, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> CommandResult
async
¶
Un mode fuera de soft/mixed/hard/merge/keep es
InvalidArgumentException sin ejecutar nada.
restore(path: str, paths: Sequence[str], staged: bool | None = None, worktree: bool | None = None, source: str | None = None, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> CommandResult
async
¶
Sin staged ni worktree restaura el árbol de trabajo;
staged=True solo saca del índice. Una lista vacía es
InvalidArgumentException sin ejecutar nada.
push(path: str, remote: str | None = None, branch: str | None = None, set_upstream: bool = True, username: str | None = None, password: str | None = None, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> CommandResult
async
¶
git push. Con credenciales: remote get-url, remote set-url
con la URL con credenciales, el push y, pase lo que pase, remote
set-url con la URL original.
pull(path: str, remote: str | None = None, branch: str | None = None, username: str | None = None, password: str | None = None, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> CommandResult
async
¶
git pull. Sin remote ni branch exige una rama con upstream
(GitUpstreamException si no la hay); las credenciales se inyectan y
se retiran como en push.
set_config(key: str, value: str, scope: str = 'global', path: str | None = None, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> CommandResult
async
¶
git config --global|--local|--system; scope="local" necesita path.
get_config(key: str, scope: str = 'global', path: str | None = None, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> str | None
async
¶
El valor, o None si la clave no está en ese scope.
dangerously_authenticate(username: str, password: str, host: str = 'github.com', protocol: str = 'https', envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> CommandResult
async
¶
Autentica git para todo el sandbox con el helper store:
credential.helper=store global y git credential approve.
Las credenciales quedan en ~/.git-credentials del usuario del
sandbox y son visibles para cualquier código que corra en él, igual
que en E2B. Usa tokens de vida corta. El SDK nunca las loguea.
configure_user(name: str, email: str, scope: str = 'global', path: str | None = None, envs: Mapping[str, str] | None = None, user: str | None = None, cwd: str | None = None, timeout: float | None = None, request_timeout: float | None = None) -> CommandResult
async
¶
user.name y user.email en el scope pedido.
GitStatus(current_branch: str | None, upstream: str | None, ahead: int, behind: int, detached: bool, file_status: list[GitFileStatus] = list())
dataclass
¶
El estado de un repositorio tal como lo modela E2B.
GitFileStatus(name: str, status: str, index_status: str, working_tree_status: str, staged: bool, renamed_from: str | None = None)
dataclass
¶
Una entrada de git status --porcelain=1: status normalizado
(modified, added, untracked, conflict...) y los dos caracteres
crudos del índice y del árbol de trabajo.
GitBranches(branches: list[str] = list(), current_branch: str | None = None)
dataclass
¶
GitResetMode is the alias Literal["soft", "mixed", "hard", "merge", "keep"]
for the mode= of git.reset().
AI agent (sbx.agent)¶
run() runs the agent to completion (raises AgentException if it fails);
stream() returns an iterable AgentStream that never raises on an agent
failure; prepare() triggers the runtime warm-up in the background.
Agent(sandbox: AgentSandbox)
¶
El agente de IA de este sandbox (ai-agent-core, ADR-025). Una
instancia por Sandbox, creada en su constructor (como
.commands/.files): tocarla no hace ninguna llamada; el coste
empieza con el primer run()/stream().
Coste y activación¶
Activa: llamar a run(), stream() o prepare(). No hace falta
ninguna opción nueva: basta con usar sbx.agent.
Recursos y llamadas AWS: ninguno nuevo de Rayito. El propio runtime
llama al modelo (Bedrock Converse/ConverseStream, o la API que
exponga la pasarela) a través de la pasarela ya configurada con
gateways= en create(); sin ella, run()/stream() fallan con
InvalidArgumentException antes de cualquier llamada. El sandbox
ya factura por segundo, con o sin agente.
Coste aproximado: depende del modelo y de los pasos, no de Rayito.
Guía con precios de lista (us-east-1, consultados 2026-10-06,
https://aws.amazon.com/bedrock/pricing y
https://aws.amazon.com/lambda/pricing/): 10 pasos de Haiku 4.5
regional (15k tokens de entrada + 400 de salida por paso) ≈ $0,187
sin caché / $0,083 con caché de prompts; 5 minutos de MicroVM de
2 GB ≈ $0,0119. El modelo cuesta entre 7x y 21x la VM (cost.md,
"Coste de un agente").
IAM: ninguno adicional a lo que ya pide la pasarela (SecretGateway,
secretsmanager:GetSecretValue).
Cómo apagarla: no llames a sbx.agent.run()/stream()/prepare().
Ejemplo:
model_id = "us.anthropic.claude-haiku-4-5-20251001-v1:0"
with Sandbox.create(
"rayito-agent",
allow_internet_access=False,
gateways={"bedrock": bedrock_gateway(
"bedrock-key", region="us-east-1", models=[model_id],
)},
) as sbx:
result = sbx.agent.run(
"lista los ficheros de /home/user",
spec=AgentSpec(model=AgentModel(
provider="bedrock", id=model_id,
gateway="bedrock", region="us-east-1",
)),
)
run(prompt: str, *, spec: AgentSpec, runtime: str | AgentRuntime = DEFAULT_AGENT_RUNTIME, session_id: str | None = None, model: str | None = None, limits: AgentLimits | None = None, workdir: str = DEFAULT_AGENT_WORKDIR, reasoning: bool = False) -> AgentResult
¶
Corre el agente hasta que termina y devuelve su AgentResult.
Una ejecución fallida lanza AgentException (el último evento era
AgentFailed); un fallo de sandbox o de transporte (SandboxException,
TimeoutException) se propaga tal cual.
stream(prompt: str, *, spec: AgentSpec, runtime: str | AgentRuntime = DEFAULT_AGENT_RUNTIME, session_id: str | None = None, model: str | None = None, limits: AgentLimits | None = None, workdir: str = DEFAULT_AGENT_WORKDIR, reasoning: bool = False) -> AgentStream
¶
Como run(), pero devuelve un AgentStream iterable que nunca
lanza por un fallo del agente: el último evento es Done o
AgentFailed. Un fallo de sandbox o de transporte sí se propaga,
al construir el stream o al iterarlo.
prepare(*, runtime: str | AgentRuntime = DEFAULT_AGENT_RUNTIME) -> None
¶
Dispara los pasos de calentamiento del runtime (warmup_steps)
en segundo plano y vuelve enseguida: no espera a ninguno. Un paso
con background=True corre sin plazo: es un proceso que debe seguir
vivo y moriría al agotarlo.
AgentStream(*, sandbox: AgentSandbox, handle: CommandHandle, runtime: AgentRuntime, state: RuntimeState, limits: AgentLimits, session_id: str | None, span_context: AbstractContextManager[Any], span: Any)
¶
Iterable de AgentEvent sobre un CommandHandle en background:
cada chunk de stdout se troceaba en líneas, cada línea se traduce con
el adaptador del runtime y cada evento pasa por LimitTracker antes de
entregarse. Nunca lanza por un fallo del agente; result() sí.
AsyncAgentStream(*, sandbox: AgentSandbox, handle: AsyncCommandHandle, runtime: AgentRuntime, state: RuntimeState, limits: AgentLimits, session_id: str | None, span_context: AbstractContextManager[Any], span: Any)
¶
Espejo asíncrono de sandbox_sync.agent.AgentStream: implementa
AsyncIterable[AgentEvent]. Cancelar la tarea que corre __anext__
(o un async with del que se sale por cancelación) dispara abort().
abort() -> None
async
¶
Para los procesos que lanzó el runtime y mata el proceso.
Specification¶
AgentSpec(model: AgentModel, small_model: str | None = None, instructions: str | None = None, mcp: Mapping[str, McpServer] = dict(), permissions: AgentPermissions = AgentPermissions(), agents: Mapping[str, SubAgent] = dict(), raw_config: Mapping[str, object] | None = None, runtime_version: str | None = None)
dataclass
¶
La configuración estática de un agente: modelo, instrucciones, servidores MCP, permisos y subagentes. Construirlo no llama a nada.
small_model (títulos, resúmenes) es por defecto model.id, así que el
runtime nunca elige por su cuenta un modelo que la cuenta quizá no tenga.
instructions se escribe en un AGENTS.md propio bajo
AGENT_STATE_DIR, nunca sobre el del directorio de trabajo (que OpenCode
también lee). raw_config se fusiona en profundidad al final y no puede
tocar RESERVED_CONFIG_KEYS. runtime_version sólo se valida como
texto: hoy no se compara con el manifiesto de la plantilla y nunca
produce runtime_version_mismatch.
gateway_names() -> frozenset[str]
¶
Las pasarelas que el agente necesita: la del modelo y la de cada
McpRemote.
require_gateways(available: Collection[str]) -> None
¶
Falla con InvalidArgumentException si alguna pasarela de
gateway_names() no está en available (los nombres de
sbx.gateways). Un nombre de pasarela nunca es secreto.
AgentModel(provider: ModelProvider, id: str | None, gateway: str, region: str | None = None, base_path: str = '', prompt_caching: bool = True, id_env: str | None = None, base_url_env: str | None = None, api_key_env: str | None = None)
dataclass
¶
El modelo que usa el agente y la pasarela por la que llega a él.
gateway nombra una entrada de sbx.gateways (un SecretGateway ya
aplicado, por ejemplo con bedrock_gateway(...)); si el sandbox no la
tiene, sbx.agent.run() falla con InvalidArgumentException antes de
cualquier RPC. region es obligatoria con provider="bedrock".
base_path sólo se usa con "openai-compatible" ("/v1") y es el
del preset: "/api/v1" con openrouter_gateway, "/openai/v1" con
groq_gateway, "/v1" con mistral_gateway y litellm_gateway, ""
con deepseek_gateway. "openai" va con openai_gateway o
xai_gateway, "google" con gemini_gateway y "azure" con
azure_openai_gateway; esos tres fijan su ruta en el adaptador.
prompt_caching=True deja que el runtime marque puntos de caché
(Bedrock cachePoint, Anthropic cache_control): con dos o más pasos
abarata la entrada repetida.
id=None es un modelo que elige el código del agente por su
configuración (ADR-033 D2): sólo vale con un runtime que no construye el
modelo (un entrypoint tuyo) y una pasarela que no filtra por modelo.
id_env, base_url_env y api_key_env son los nombres de las
variables de entorno en las que tu código lee el id, la URL base y la
clave ("LLM_MODEL", "LLM_BASE_URL", "LLM_API_KEY"); nunca valores.
En MicroVMs Rayito las apunta a la pasarela y al marcador de la clave.
env_names() -> dict[str, str]
¶
Las claves MODEL_ENV_KEYS que están puestas y el nombre de su
variable, en ese orden.
AgentLimits(max_steps: int = DEFAULT_AGENT_MAX_STEPS, timeout_seconds: float = DEFAULT_AGENT_TIMEOUT_SECONDS, max_output_bytes: int = DEFAULT_AGENT_MAX_OUTPUT_BYTES, max_total_tokens: int | None = DEFAULT_AGENT_MAX_TOTAL_TOKENS)
dataclass
¶
Topes duros de una ejecución, impuestos por el SDK (no por el
runtime): max_steps aborta con max_steps al empezar el paso
max_steps + 1; max_total_tokens se comprueba tras cada paso, así que
puede pasarse en un paso (None lo desactiva); timeout_seconds y
max_output_bytes son los del comando que corre el runtime. Los valores
por defecto acotan el coste de una ejecución (design.md de
ai-agent-core, D4).
AgentPermissions(default: PermissionAction = 'allow', tools: Mapping[str, ToolPermission] = dict())
dataclass
¶
Qué herramientas puede usar el agente. default aplica a toda
herramienta sin entrada propia; tools asigna "allow"/"deny" a una
herramienta ("edit": "deny") o a patrones de su argumento
("bash": {"git *": "allow", "*": "deny"}). "ask" no existe: la
ejecución es desatendida.
No es una frontera de seguridad (SECURITY.md T29): la frontera es la
MicroVM con el egress cerrado. effective_tools() añade
DEFAULT_DENIED_TOOLS por debajo de las entradas del llamante.
effective_tools() -> Mapping[str, ToolPermission]
¶
DEFAULT_DENIED_TOOLS en "deny" y encima las entradas de
tools (una entrada del llamante gana).
SubAgent(description: str, instructions: str, model: str | None = None, permissions: AgentPermissions | None = None)
dataclass
¶
Un subagente que el agente principal puede invocar (OpenCode
mode: subagent, deepagents subagents=). model es un id del mismo
proveedor y pasarela que AgentSpec.model; None hereda el suyo.
McpLocal(command: Sequence[str], envs: Mapping[str, str] = dict(), timeout_seconds: float | None = None)
dataclass
¶
Un servidor MCP que el runtime arranca dentro del sandbox como
proceso hijo (command en forma de lista, sin shell). envs se escribe
en la configuración del runtime, legible por uid 1000: nunca pongas ahí
una credencial, usa una pasarela.
McpRemote(gateway: str, path: str = '/')
dataclass
¶
Un servidor MCP remoto alcanzado a través de la pasarela gateway
(la URL sale de sbx.gateways[gateway].url + path). No hay
headers a propósito: la credencial sólo la pone la pasarela.
McpServer is the alias McpLocal | McpRemote.
DeepAgents(entrypoint: str | None = None, *, require_entrypoint: bool = False, requirements: str | None = None, package_manager: str | None = None)
¶
AgentRuntime de deepagents (runtime=DeepAgents(...) o
runtime="deepagents").
Sin entrypoint, el runner construye create_deep_agent(model,
system_prompt=instructions, subagents, backend=LocalShellBackend(
root_dir=workdir), middleware=ctx.middleware). Con entrypoint=
"pkg.mod:build", importa ese módulo desde el directorio de trabajo y
llama a build(ctx) con un RunnerContext(model, instructions,
subagents, backend, middleware, workdir); debe devolver un grafo
compilado. Si no pasa ctx.middleware a su grafo, se pierden los
permisos de AgentSpec.
require_entrypoint=True es el runtime registrado como "langgraph": el
mismo adaptador, pero sin entrypoint no hay agente que construir y
build_config() / host_config() fallan con InvalidArgumentException.
El modelo siempre llega por la pasarela (ChatBedrockConverse,
ChatAnthropic o ChatOpenAI con la URL de la pasarela y un marcador
como clave). deepagents marca puntos de caché de prompts para Claude
(Bedrock y Anthropic); AgentModel(prompt_caching=False) lo apaga.
command(request: RunRequest) -> RunCommand
¶
El script (cerrojo, comprobación del runner, exec del Python
del venv) y la petición JSON por stdin.
parse_line(line: bytes, state: RuntimeState) -> Sequence[AgentEvent]
¶
Una línea del protocolo v1 a cero o un evento. Lo que no es JSON, otra versión o un tipo desconocido se ignora y se cuenta.
finish(state: RuntimeState, exit_code: int) -> Done | AgentFailed
¶
Done sólo con salida 0, el done del runner y una sesión.
template_steps() -> Sequence[TemplateStep]
¶
Vacío: la plantilla de agente (ai-agent-fast-start) declara sus
propios pasos.
warmup_steps() -> Sequence[WarmupStep]
¶
Carga deepagents y langchain en la caché de páginas.
install_steps(target: InstallTarget) -> Sequence[TemplateStep]
¶
Copia los requisitos con hash, crea el venv con --require-hashes,
añade las dependencias de tu proyecto (requirements, con pip o
uv) sin quitar lo que ya hay y copia el runner (0755).
context_files() -> Mapping[str, bytes]
¶
Los requisitos con hash y el runner (datos de paquete).
manifest_entry() -> Mapping[str, object]
¶
El sha256 de los requisitos y el del runner, para el manifiesto, y los de tu proyecto si los pediste.
smoke_checks() -> Sequence[str]
¶
Importa deepagents y los modelos de cada proveedor, y comprueba
que el runner es legible, todo como user.
prefetch_paths() -> Sequence[str]
¶
Ninguna: el venv se carga con warmup_steps().
host_config(spec: AgentSpec, *, wiring: ModelWiring, workdir: str) -> HostConfig
¶
La configuración del host para el driver deepagents: el mismo
fichero de configuración y las mismas variables que command(), más
las estándar del proveedor apuntadas a la pasarela, para que también
el cliente de modelo que crea tu grafo pase por ella.
Model gateways¶
They build the SecretGateway that AgentModel.gateway names.
bedrock_gateway(secret: str | SecretRef, *, region: str, models: Sequence[str], rate_per_minute: int = 0) -> SecretGateway
¶
Pasarela hacia Bedrock (Converse/ConverseStream) para los
models dados (ids o perfiles de inferencia, como
us.anthropic.claude-haiku-4-5-20251001-v1:0). secret nombra un
secreto con Bearer <clave de API de Bedrock>; una clave de corta
duración se rota con sbx.gateways.refresh().
anthropic_gateway(secret: str | SecretRef, *, rate_per_minute: int = 0) -> SecretGateway
¶
Pasarela hacia la Messages API de Anthropic. secret nombra un
secreto con la clave de API (x-api-key).
openai_compatible_gateway(secret: str | SecretRef, *, upstream: str, base_path: str = '', rate_per_minute: int = 0) -> SecretGateway
¶
Pasarela hacia una API compatible con OpenAI (POST
<base_path>/chat/completions). upstream es https://host;
base_path es el mismo que AgentModel.base_path ("/v1"). secret
nombra un secreto con Bearer <clave>.
Result and events¶
AgentEvent is the alias of the closed union of events that
agent.stream() yields: TextDelta | Text | Reasoning | ToolCall | StepStarted |
StepFinished | AgentFailed | Done.
AgentResult(session_id: str, text: str, steps: int, usage: TokenUsage, exit_code: int, tool_calls: tuple[ToolCall, ...] = (), dropped_lines: int = 0, usage_reported: bool = True, output: Mapping[str, Any] | None = None)
dataclass
¶
El resultado de sbx.agent.run(). text es el último Text del
asistente; dropped_lines cuenta las líneas del runtime descartadas
(tipo desconocido o más largas que MAX_AGENT_EVENT_LINE_BYTES).
usage_reported es False si el agente no informó de tokens (una app
HTTP, un comando o una función propios que no devuelven usage): usage
vale entonces cero porque se desconoce, no porque no se gastara nada.
output es la salida estructurada (un objeto JSON) de un grafo invocado
con input; None en cualquier otro caso.
TokenUsage(input: int = 0, output: int = 0, reasoning: int = 0, cache_read: int = 0, cache_write: int = 0)
dataclass
¶
Tokens de un paso o de una ejecución. input excluye los leídos de
caché (cache_read) y los escritos en ella (cache_write), como
Bedrock y Anthropic los facturan por separado; total suma los cinco.
El SDK no da un coste: los precios dependen de región y perfil.
TextDelta(text: str)
dataclass
¶
Un trozo de texto en curso (sólo deepagents; OpenCode emite Text
entero).
Text(text: str)
dataclass
¶
Un bloque de texto completo del asistente.
Reasoning(text: str)
dataclass
¶
Razonamiento del modelo; sólo con run(..., reasoning=True).
ToolCall(call_id: str, name: str, status: ToolCallStatus, input: Mapping[str, object] | None = None, output: str | None = None, output_truncated: bool = False)
dataclass
¶
Una herramienta terminada. output llega recortado a
MAX_TOOL_OUTPUT_PREVIEW_BYTES (output_truncated).
StepStarted(index: int)
dataclass
¶
Empieza el paso index (desde 1): una llamada al modelo.
StepFinished(index: int, usage: TokenUsage, finish_reason: str | None = None)
dataclass
¶
Termina el paso index con sus tokens.
AgentFailed(reason: AgentFailureReason, exit_code: int | None = None, detail_code: str | None = None, session_id: str | None = None)
dataclass
¶
Último evento de una ejecución fallida. reason es de
AGENT_FAILURE_REASONS; detail_code se descarta si no es un
identificador corto.
to_exception(usage: TokenUsage | None = None) -> AgentException
¶
La AgentException que sbx.agent.run() lanza por este evento.
Done(session_id: str, exit_code: int, usage: TokenUsage, usage_reported: bool = True, output: Mapping[str, Any] | None = None)
dataclass
¶
Último evento de una ejecución correcta, con los tokens acumulados.
usage_reported es False cuando el agente no informó de tokens (una app
HTTP, un comando o una función propios): usage es entonces cero porque
se desconoce, no porque no se gastara nada. output es la salida
estructurada de un grafo llamado con input (None si no la hay). Es
un InitVar guardado como atributo y no un campo: dataclasses.asdict,
repr y la igualdad de un Done no cambian (los vectores de eventos ya
publicados lo comparan así), y dataclasses.replace lo conserva.
Image and fast start¶
AgentTemplate builds the image with the runtime once
(Agent templates);
with it, the normal start is Sandbox.create(...) + sbx.agent.run(...).
agent_pool_warmup and warm pools are optional:
What do I use?.
AgentTemplate(name: str = DEFAULT_AGENT_TEMPLATE_NAME, base: str = DEFAULT_AGENT_TEMPLATE_BASE, runtimes: tuple[str | AgentRuntime, ...] = AGENT_TEMPLATE_RUNTIMES, prefetch: bool = True, kernel_warmup: bool = False, memory_mib: int = AGENT_MIN_MEMORY_MIB, base_version: str | None = None, app: str | None = None, app_exclude: tuple[str, ...] = ())
dataclass
¶
Plantilla de imagen con los runtimes del agente de IA.
runtimes elige qué se instala: nombres del registro ("opencode",
"deepagents", "langgraph"...) u objetos que implementen
InstallableRuntime; la imagen se compone con los install_steps() de
cada uno. app es un directorio local con el código del agente: se copia
a AGENT_APP_DIR (de root, sin escritura para user) con las reglas de
su .dockerignore más app_exclude (patrones de .dockerignore).
prefetch=True hornea el demonio que precarga los binarios en la caché
de páginas tras cada restauración del snapshot. kernel_warmup=False
(por defecto) apaga el calentamiento del kernel de run_code (numpy,
pandas, matplotlib, scipy y scikit-learn importados en cada arranque del
kernel, también en la rotación que create() espera): medido en AWS
(AWS_API_NOTES.md Q155), create() vuelve 4,4 s antes (p50) y el
snapshot de memoria pesa 248 MB menos, con el mismo primer token del
agente; a cambio, la primera celda de run_code que importe ese stack
paga la importación. kernel_warmup=True deja el kernel como en la
imagen base. memory_mib por debajo de AGENT_MIN_MEMORY_MIB (2048,
el RSS medido de OpenCode) es InvalidArgumentException.
Coste y activación¶
Activa: AgentTemplate(...).build(bucket=...) o
rayito agent template build.
Recursos y llamadas AWS: los de Template.build (un build de imagen,
s3:PutObject del contexto, una versión de imagen nueva); nada si
no se construye.
Coste aproximado: build de 260-320 s (medido en AWS, 2026-10-07 y
2026-10-09); la versión almacenada ≈ 3,0 GB (código 2,10 + memoria
0,86 + disco 0,03; memoria 0,92 con kernel_warmup=True) por
$0,08/GB-mes, con el mínimo de una semana ≈ $0,056/semana
(≈ $0,24/mes) por versión, y cada lanzamiento lee el snapshot de
memoria (≈ 0,86 GB por $0,00155/GB ≈ $0,0013).
Estimación con precios de lista de Lambda MicroVMs, us-east-1,
consultados 2026-10-06 (https://aws.amazon.com/lambda/pricing/).
IAM: la política RayitoTemplateBuilder (la misma que Template.build).
Cómo apagarla: no la construyas; borra sus versiones con rayito image.
Ejemplo:
AgentTemplate(runtimes=("opencode",)).build(bucket="amzn-s3-demo-bucket")
installables() -> tuple[InstallableRuntime, ...]
¶
Los runtimes de la plantilla, ya resueltos.
manifest() -> dict[str, object]
¶
El manifiesto rayito.agent-template/1 que se hornea en
AGENT_TEMPLATE_MANIFEST_PATH: versiones y hashes de lo instalado,
protocolo, las rutas que precarga el demonio y, desde ADR-028, la
entrada de cada runtime (runtimes) y el sha256 del host del agente
(host_sha256).
context_files() -> dict[str, bytes]
¶
Los ficheros del contexto de build (nombre relativo -> bytes). El
código del usuario (app) no entra aquí: lo escribe build().
to_template(template_class: type[Template] = Template) -> Template
¶
El Template equivalente (puro: no lee ni escribe nada).
build(*, bucket: str, force: bool = False, timeout: float = DEFAULT_BUILD_TIMEOUT_SECONDS, on_build_logs: Callable[[str], None] | None = None, region: str | None = None, session: Any = None) -> BuildInfo
¶
Construye la imagen name con Template.build (ver el bloque
de coste de la clase).
AsyncAgentTemplate(name: str = DEFAULT_AGENT_TEMPLATE_NAME, base: str = DEFAULT_AGENT_TEMPLATE_BASE, runtimes: tuple[str | AgentRuntime, ...] = AGENT_TEMPLATE_RUNTIMES, prefetch: bool = True, kernel_warmup: bool = False, memory_mib: int = AGENT_MIN_MEMORY_MIB, base_version: str | None = None, app: str | None = None, app_exclude: tuple[str, ...] = ())
dataclass
¶
agent_pool_warmup(runtime: str | AgentRuntime = DEFAULT_AGENT_RUNTIME) -> tuple[WarmupStep, ...]
¶
Los pasos de PoolConfig(warmup=...) para un pool de agentes: cargan
el runtime en la caché de páginas antes de aparcar cada plaza.
Un pool sólo compensa si llegan muchas conversaciones nuevas cuyo
primer mensaje tiene que ser rápido: los turnos de una misma
conversación de menos de 8 h van mejor en una sola VM pausada entre
turnos (pause() y connect(), o la auto-suspensión de IdlePolicy),
y más allá de 8 h, con persist=. Guía "Agente en el sandbox",
"¿Qué uso?".
Coste y activación¶
Activa: PoolConfig(warmup=agent_pool_warmup(...)).
Recursos y llamadas AWS: ninguna llamada nueva; cada plaza corre los
pasos antes de su pause() y su snapshot crece con la caché.
Coste aproximado: ≈ $0,0054 por ciclo de reciclado (≈ 103 al mes) ≈
$0,64/plaza/mes, frente a ≈ $0,60 de una plaza base; cada take()
lee ≈ $0,0014. Tiempos medidos en AWS (AWS_API_NOTES Q147) por
precios de lista, us-east-1, consultados 2026-10-06
(https://aws.amazon.com/lambda/pricing/).
IAM: ninguna además de la del pool.
Cómo apagarla: PoolConfig(warmup=()) (por defecto).
Ejemplo:
PoolConfig(size=2, template="rayito-agent", allow_internet_access=False,
warmup=agent_pool_warmup("opencode"))
WarmupStep(cmd: str, background: bool = False, timeout_seconds: float = DEFAULT_WARMUP_STEP_TIMEOUT_SECONDS, tag: str | None = None)
dataclass
¶
Un paso de calentamiento: agent.prepare() y el warmup= de un pool
(B2) corren la misma lista. background=True no espera a que termine
(un proceso que sigue vivo); si no, se espera su salida con timeout_seconds.
Agent runtimes and deployment¶
The runtimes that AgentTemplate, Agent and AgentProject accept. They install their dependencies with pinned hashes and send the model through the secrets gateway (Deploy your agent).
StrandsRuntime(entrypoint: str | None = None, harness: bool = False, language: StrandsLanguage = 'python', requirements: str | None = None, package_manager: str | None = None, node_version: str | None = None)
¶
Bases: HostBackedRuntime
AgentRuntime de Strands Agents (runtime=StrandsRuntime(...);
"strands" y "strands-harness" en el registro).
entrypoint es modulo:atributo en Python (un Agent o una función
fn(ctx) -> Agent) y la ruta de un módulo bajo AGENT_APP_DIR en
TypeScript (obligatoria, y exporta agent o createAgent(ctx)).
harness=True usa create_harness del paquete strands-harness
(sólo con language="python"; en TypeScript el harness se importa en tu
código). requirements es un fichero de requisitos de tu source
(app/<requirements>) que se instala en el venv después de los pines de
Rayito (sólo Python). Con language="typescript" el source debe llevar
package.json y package-lock.json: el build ejecuta npm ci
--ignore-scripts con ellos y falla si faltan.
Coste y activación¶
Activa: pasar StrandsRuntime(...) o runtime="strands" /
"strands-harness" a AgentTemplate, AgentProject o
sbx.agent.run.
Recursos y llamadas AWS: ninguna por sí solo; la imagen que lo instala
se construye con AgentTemplate.build (un build de imagen) y cada
ejecución llama al modelo de la pasarela que elijas.
Coste aproximado: el del build de la imagen (ver AgentTemplate) más el
del modelo; el venv de Strands añade unos 0,3 GB al snapshot (medido
en AWS_API_NOTES.md cuando se publique).
IAM: la política RayitoTemplateBuilder para construir; ninguna para
ejecutar (la pasarela guarda la clave).
Cómo apagarla: no incluirlo en runtimes ni en el proyecto.
Ejemplo:
AgentTemplate(runtimes=(StrandsRuntime(entrypoint="agent:agent"),))
from_options(kind: str, options: Mapping[str, object]) -> StrandsRuntime
classmethod
¶
El runtime de la tabla [runtime] de rayito-agent.toml
(kind es "strands" o "strands-harness").
to_options() -> dict[str, object]
¶
La tabla [runtime] canónica: kind y sus opciones.
wiring_envs(spec: AgentSpec, urls: Mapping[str, str] | None) -> Mapping[str, str]
¶
Las variables estándar del proveedor apuntadas a la pasarela (ver
standard_model_envs).
install_steps(target: InstallTarget) -> Sequence[TemplateStep]
¶
Python: los requisitos con hash, el venv (--require-hashes) y,
si hay, los del usuario. TypeScript: Node (sha256 fijado), la
instalación congelada de tu lockfile (npm, pnpm o yarn) y el
puente.
manifest_entry() -> Mapping[str, object]
¶
Versiones y hashes de lo instalado, para el manifiesto.
smoke_checks() -> Sequence[str]
¶
Importa el SDK (y el harness) como user.
prefetch_paths() -> Sequence[str]
¶
El binario de Node (TypeScript); el venv de Python se carga con
warmup_steps().
warmup_steps() -> Sequence[WarmupStep]
¶
Carga Strands (o Node con el SDK) en la caché de páginas.
HermesRuntime(toolsets: Sequence[str] = HERMES_DEFAULT_TOOLSETS, skills_dir: str | None = None)
¶
Bases: HostBackedRuntime
AgentRuntime de Hermes Agent (runtime=HermesRuntime(...) o
runtime="hermes").
toolsets son los toolsets de Hermes que se activan (por defecto
terminal y ficheros); los que AgentPermissions deniega del todo se
quitan. skills_dir es una carpeta de skills de tu source
(app/<skills_dir>) que Hermes lee como directorio externo, de sólo
lectura.
Coste y activación¶
Activa: pasar HermesRuntime() o runtime="hermes" a AgentTemplate,
AgentProject o sbx.agent.run.
Recursos y llamadas AWS: ninguna por sí solo; la imagen que lo instala
se construye con AgentTemplate.build (un build de imagen) y cada
ejecución llama al modelo de la pasarela que elijas.
Coste aproximado: el del build de la imagen (ver AgentTemplate) más el
del modelo; Hermes suma unos 0,5 GB (CPython 3.14, venv y fuente),
así que la imagen es más grande y arranca más despacio que la de
Strands (se mide en AWS_API_NOTES.md al publicar).
IAM: la política RayitoTemplateBuilder para construir; ninguna para
ejecutar (la pasarela guarda la clave).
Cómo apagarla: no incluirlo en runtimes ni en el proyecto.
Ejemplo:
AgentTemplate(runtimes=(HermesRuntime(),))
from_options(options: Mapping[str, object]) -> HermesRuntime
classmethod
¶
El runtime de la tabla [runtime] de rayito-agent.toml.
to_options() -> dict[str, object]
¶
La tabla [runtime] canónica.
host_python() -> str
¶
El host (stdlib) corre con el Python de Hermes: es el único intérprete garantizado en la imagen que ya lo trae.
wiring_envs(spec: AgentSpec, urls: Mapping[str, str] | None) -> Mapping[str, str]
¶
Bedrock y Anthropic por sus variables estándar (el marcador como
clave y la pasarela como endpoint); provider: custom lo lleva la
configuración, y las variables de OpenAI no se exportan para no
confundir la resolución de proveedor de Hermes.
install_steps(target: InstallTarget) -> Sequence[TemplateStep]
¶
CPython 3.14 independiente (sha256 fijado), venv con
--require-hashes y el checkout del tag verificado contra su
commit y recortado.
manifest_entry() -> Mapping[str, object]
¶
Versión, commit, CPython y hashes de lo instalado.
smoke_checks() -> Sequence[str]
¶
Importa Hermes y su API HTTP como user.
prefetch_paths() -> Sequence[str]
¶
Ninguna: se carga con warmup_steps().
warmup_steps() -> Sequence[WarmupStep]
¶
Carga Hermes en la caché de páginas.
CustomRuntime(install: Sequence[str] = (), requirements: str | None = None, command: Sequence[str] | None = None, entrypoint: str | None = None, app: HttpApp | None = None, protocol: CustomProtocol = DEFAULT_CUSTOM_PROTOCOL, python: str | None = None, package_manager: str | None = None, python_version: str | None = None, node_version: str | None = None, adapter: str | None = None)
¶
Bases: HostBackedRuntime
AgentRuntime del agente que escribes tú (ver el módulo).
install son órdenes de shell que se ejecutan al construir la imagen
(como root, antes de copiar tu source), por ejemplo un npm ci o un
dnf install. requirements es un fichero de dependencias de tu source
(app/<requirements>: requirements.txt o, con package_manager="uv",
pyproject.toml o uv.lock): se instala en un venv propio, que pasa a
ser el intérprete del host y de tu función. python es el intérprete con
el que corre todo (por defecto python3).
package_manager elige el gestor: pip o uv (Python) o npm, pnpm o
yarn (Node: source debe llevar package.json y su lockfile, y la
instalación es la congelada del gestor). python_version (3.11...) y
node_version (22, 24) piden un intérprete distinto del de la imagen:
se baja un build con sha256 fijado. adapter (callable, langgraph o
vercel-ai) dice cómo el puente de Node ejecuta un entrypoint
ruta.ts#exportacion.
Coste y activación¶
Activa: pasar CustomRuntime(...) a AgentTemplate, AgentProject o
sbx.agent.run.
Recursos y llamadas AWS: ninguna por sí solo; la imagen que lo instala
se construye con AgentTemplate.build (un build de imagen) y cada
ejecución llama al modelo de la pasarela que elijas.
Coste aproximado: el del build de la imagen (ver AgentTemplate) más el
del modelo; lo que añada tu install y tus requisitos.
IAM: la política RayitoTemplateBuilder para construir; ninguna para
ejecutar (la pasarela guarda la clave).
Cómo apagarla: no incluirlo en runtimes ni en el proyecto.
Ejemplo:
CustomRuntime(entrypoint="agente:responde", requirements="requirements.txt")
from_options(options: Mapping[str, object]) -> CustomRuntime
classmethod
¶
El runtime de la tabla [runtime] de rayito-agent.toml.
to_options() -> dict[str, object]
¶
La tabla [runtime] canónica.
venv_bin(install_dir: str = AGENT_INSTALL_DIR) -> str
¶
El bin del venv de requirements: va el primero en el PATH de
tu app o tu comando, de modo que python y pip son los suyos.
wiring_envs(spec: AgentSpec, urls: Mapping[str, str] | None) -> Mapping[str, str]
¶
Las variables estándar del proveedor más las RAYITO_MODEL_*
(RAYITO_MODEL_ID sólo si se conoce el id).
install_steps(target: InstallTarget) -> Sequence[TemplateStep]
¶
Tus órdenes de install y el toolchain que pidas: con
requirements, el venv con tus dependencias; con un gestor de Node,
Node y la instalación congelada de tu lockfile (y el puente si hay
entrypoint).
context_files() -> Mapping[str, bytes]
¶
El puente de Node si hay un entrypoint de JavaScript; si no,
ninguno: tu código y tus requisitos van en source.
manifest_entry() -> Mapping[str, object]
¶
Qué se instaló: el driver, el hash de tus órdenes y tus requisitos, y el gestor y las versiones de intérprete que pediste.
smoke_checks() -> Sequence[str]
¶
Node o el CPython fijado, si los pediste; si no, ninguna: no sabemos qué instalas.
HttpApp(command: Sequence[str], port: int, health_path: str = AGENT_SERVICE_HEALTH_PATH, invoke_path: str = AGENT_SERVICE_INVOKE_PATH, protocol: HttpAppProtocol = DEFAULT_HTTP_APP_PROTOCOL, request_field: str | None = None, response_field: str | None = None, port_env: str | None = None, assistant_id: str | None = None)
dataclass
¶
Tu servidor HTTP (CustomRuntime(app=HttpApp(...))): command lo
arranca, port es donde escucha (dentro del sandbox), health_path es
la ruta que debe contestar 200 cuando está listo e invoke_path la que
recibe {"prompt": ...}. protocol es "agentcore" (el contrato de
AgentCore), "json" (una app con su propio contrato JSON),
"openai-chat" (Chat Completions con streaming) o "raw" (sólo se
expone).
Cuándo cada uno: con "agentcore" u "openai-chat" el host sirve
/ping y /invocations y traduce a tu invoke_path, así que
deployment.invoke() funciona pero tus rutas propias no se alcanzan
desde fuera; con "json" el host traduce igual (el prompt va en
request_field, por defecto prompt, y el texto sale de
response_field, o del primer campo de texto de answer, output,
text, response, result o content) y además reenvía tus demás
rutas, de modo que invoke() funciona y tu /health o tu /chat
siguen alcanzables; con "raw" el despliegue reenvía tus rutas tal cual
(un servidor MCP) y invoke() no existe: usa deployment.url y
deployment.headers con tu cliente. port_env es la variable de
entorno con la que se le dice a tu app en qué port escuchar (por
ejemplo PORT).
Con "langgraph-api" (experimental, ADR-033 D5) tu command es
langgraph dev y el host traduce cada invocación a
POST /threads/{thread_id}/runs/wait del LangGraph Platform API: el
hilo sale de la sesión y assistant_id (obligatorio, y sólo con este
protocolo) es el grafo de langgraph.json que se ejecuta. La salud es
/ok si dejas health_path por defecto, la ruta de invocación la fija
el API (invoke_path no se cambia) y el texto sale de response_field
o del último mensaje. Sólo /ping e /invocations se exponen: el
resto del Platform API no se alcanza desde fuera. Tu command se
ejecuta con el directorio del código copiado como directorio de trabajo y
en su PYTHONPATH; con requirements, python y pip son los del venv
(sin él, python es el intérprete de la imagen).
served_health_path: str
property
¶
La ruta de salud a la que llama el host: health_path, o /ok
con langgraph-api si se dejó la de por defecto.
served_invoke_path: str
property
¶
La ruta de invocación a la que llama el host: invoke_path, o la
de una ejecución de un hilo (/threads/{thread_id}/runs/wait) con
langgraph-api.
hides_own_routes: bool
property
¶
Con protocol="agentcore", "openai-chat" o "langgraph-api"
el despliegue sólo expone /ping y /invocations (el host traduce
a tu invoke_path): tus rutas propias (health_path, invoke_path
distintas de esas dos) no se alcanzan desde fuera. Con
protocol="json" o "raw" se exponen tal cual. Con langgraph-api,
/ok (la salud del API, la que escribe la detección) no es una ruta
propia.
from_mapping(table: Mapping[str, object]) -> HttpApp
classmethod
¶
La tabla [runtime.app] de rayito-agent.toml.
to_mapping() -> dict[str, object]
¶
La tabla [runtime.app] canónica (sólo lo que no es el valor por
defecto).
Project and deployment¶
AgentProject builds, runs, deploys or exports an agent described in rayito-agent.toml; AgentDeployment invokes it, reads its DeploymentStatus and stops it. They cost (images and MicroVMs) and do nothing until you call the method.
AgentProject(name: str, runtime: str | AgentRuntime, spec: AgentSpec, gateways: Mapping[str, SecretGateway] = dict(), source: str | None = None, exclude: Sequence[str] = (), requirements: str | None = None, limits: AgentLimits = AgentLimits(), serve: ServeOptions = ServeOptions(), allow_internet_access: bool = False, egress: Sequence[str] | None = None, memory_mib: int = AGENT_MIN_MEMORY_MIB, base: str = DEFAULT_AGENT_TEMPLATE_BASE, template: str | None = None, base_dir: str = '.', scaling: ScalingOptions = ScalingOptions(), env: Mapping[str, str] = dict(), network: NetworkPolicy | None = None, region: str | None = None, bucket: str | None = None, base_image_version: str | None = None, language: str | None = None, framework: str | None = None, versions: RuntimeVersions = RuntimeVersions(), graph: str | None = None, secret_env: Mapping[str, SecretEnvValue] = dict(), secret_env_from: Sequence[SecretEnvSource] = (), gateway_presets: Mapping[str, str] = dict())
dataclass
¶
Un agente descrito una vez: runtime, AgentSpec, pasarelas del
modelo, código (source), red e imagen. Construirlo valida todo antes de
llamar a nadie: name, que cada pasarela que el spec necesita esté en
gateways, serve y la memoria.
runtime es un nombre del registro ("opencode", "deepagents",
"langgraph"...) o un objeto de runtime. source es el directorio con
el código del agente (se copia a AGENT_APP_DIR con exclude);
requirements, un fichero de requisitos suyo. base_dir es el
directorio contra el que to_dict() escribe las rutas relativas.
template es el nombre de una imagen ya construida (por defecto,
name).
Para servir el agente en varios VMs: scaling (ScalingOptions),
env (variables no secretas del agente), network (política
allow_out/deny_out del sandbox, que necesita rayito-base-caps),
region, bucket y base_image_version (los valores por defecto de
deploy_agent()), language y framework (lo que la detección o el
fichero declaran del proyecto) y versions (RuntimeVersions).
graph es el nombre del grafo de langgraph.json que se sirve (sólo con
el runtime langgraph); to_dict() lo escribe en lugar del
entrypoint.
gateway_presets (pasarela -> preset, p. ej. {"model": "bedrock"}) es
lo que el fichero declara en [gateways.<nombre>] preset: lo rellenan
load(), from_dict() y detect(), sirve para elegir la variable
estándar de --create-secret y to_dict() no lo escribe (cada pasarela
ya va en su forma custom), así que el documento canónico no cambia.
secret_env (nombre de variable -> nombre o ARN de un secreto, o un
SecretEnvRef) y secret_env_from (SecretEnvSource) ponen valores de
Secrets Manager en el entorno del agente al arrancar (ADR-033 D4): el
proyecto sólo lleva nombres, nunca valores, y el agente puede leer su
entorno (ver SecretEnvRef para el coste).
Coste y activación¶
Activa: nada; AgentProject(...), AgentProject.load(), from_dict() y
to_dict() son puros. Lo que cuesta son build(), run() y
deploy().
Recursos y llamadas AWS: ninguno aquí; ni se crea un cliente de AWS.
Coste aproximado: ninguno; el de las operaciones está en la
documentación de AgentTemplate (build()), de Sandbox.create()
(run()) y de deploy().
IAM: ninguna para este valor.
Cómo apagarla: no llames a build(), run() ni deploy().
Ejemplo:
project = AgentProject.load("./support-bot")
project.to_dict()
load(path: str | os.PathLike[str] = '.') -> Self
classmethod
¶
Lee rayito-agent.toml o rayito-agent.json de path (un
fichero, o un directorio donde se busca el primero de
AGENT_PROJECT_FILE_NAMES).
detect(path: str | os.PathLike[str] = '.', overrides: DetectOverrides | None = None, *, region: str | None = None) -> tuple[Self, DetectionReport | None]
classmethod
¶
El proyecto de un agente que ya tienes y su DetectionReport
(None si un fichero de proyecto completo no necesitó detectar nada),
sin ejecutar su código ni llamar a AWS. El fichero de proyecto, si
existe, gana clave por clave; lo que calla lo completa la detección
(lenguaje, framework, punto de entrada, instalación, proveedor y
modelo) y overrides fuerza lo que tú indiques. Si el caso no es
claro lanza AgentProjectException con code ambiguous,
not_detected o unsupported y la clave o bandera que lo resuelve.
from_dict(data: Mapping[str, object], *, base_dir: str, read_text: Callable[[str], str] | None = None) -> Self
classmethod
¶
El proyecto de un documento ya leído. Puro: las rutas relativas
se resuelven contra base_dir sin tocar el disco, y
instructions_file pasa por read_text (el lector que inyecta
load; sin él, esa clave es un error).
to_dict() -> dict[str, object]
¶
La forma canónica del documento, la que from_dict vuelve a leer
y que comparten los dos SDK. Omite lo que vale su valor por defecto;
el texto de las instrucciones va en línea.
build(*, bucket: str, force: bool = False, timeout: float = DEFAULT_BUILD_TIMEOUT_SECONDS, on_build_logs: Callable[[str], None] | None = None, region: str | None = None, session: Any = None) -> BuildInfo
¶
Construye la imagen del proyecto con AgentTemplate (su runtime,
su código y su memoria). Cuesta un build de imagen: ver el bloque
"Coste y activación" de AgentTemplate.
run(prompt: str, *, session_id: str | None = None, model: str | None = None, reasoning: bool = False, on_event: Callable[[AgentEvent], None] | None = None, region: str | None = None, session: Any = None) -> AgentResult
¶
Una ejecución del agente en un sandbox efímero: lo crea desde la
imagen del proyecto con sus pasarelas y su red, llama a
sbx.agent.run() y lo termina siempre, también ante un error. Para
que el sandbox sobreviva, usa deploy().
deploy(*, region: str | None = None, session: Any = None, access_token: str | None = None, keep_on_failure: bool = False) -> AgentDeployment
¶
Sirve el agente desde un MicroVM y devuelve su AgentDeployment:
crea un sandbox desde la imagen del proyecto (con serve.timeout_seconds,
serve.idle y las etiquetas de despliegue), escribe la configuración
del host, lo arranca en modo servicio y espera su marcador de listo.
Si cualquier paso falla, termina el sandbox antes de lanzar (salvo
con keep_on_failure=True).
access_token es el del sandbox (como el de Sandbox.create(); sin
él, RAYITO_ACCESS_TOKEN o uno nuevo). Con uno nuevo, el valor está en
AgentDeployment.access_token: guárdalo para reconectarte desde otro
proceso (AgentDeployment.connect(sandbox_id, access_token=...),
rayito agent invoke); sin él sólo Sandbox.kill(sandbox_id) llega al
sandbox.
Un arranque fallido lanza SandboxException con el código del fallo
y el final de la salida de error de la app, sin valores de entorno ni
credenciales. Con keep_on_failure=True el sandbox no se termina
(para entrar a depurarlo: el error lleva su id en una nota) y hace
falta access_token (o RAYITO_ACCESS_TOKEN) para poder
conectarse; termínalo tú con Sandbox.kill(sandbox_id), porque sigue
facturando. Por defecto es False.
Coste y activación¶
Activa: llamar a deploy() (o rayito agent deploy); nada más lo
crea.
Recursos y llamadas AWS: un sandbox (run-microvm) que vive hasta
serve.timeout_seconds (como mucho 8 horas) o hasta
AgentDeployment.stop(), y el token del proxy
(CreateMicrovmAuthToken, gratuito); el modelo lo llama la
pasarela del sandbox.
Coste aproximado: el del MicroVM por segundo mientras vive (2 GB:
≈ $0,14 por hora en us-east-1, consultado 2026-10-06 en
https://aws.amazon.com/lambda/pricing/; serve.idle lo suspende
y la suspensión no factura cómputo) más el del modelo del agente.
IAM: los de Sandbox.create() (RayitoSandboxRunner) y, por cada
pasarela, secretsmanager:GetSecretValue.
Cómo apagarla: AgentDeployment.stop() o rayito agent stop; no
llames a deploy() y nada se crea.
Ejemplo:
deployment = AgentProject.load("./support-bot").deploy()
deployment.invoke("Resume el README.").text
deployment.stop()
export(*, target: str = 'docker', out_dir: str | os.PathLike[str], overwrite: bool = False) -> AgentExport
¶
Escribe en out_dir un contexto de build de contenedor
linux/arm64 (target="docker" o "agentcore") sin ninguna
llamada de red ni de AWS. Falla si out_dir no está vacío, salvo con
overwrite=True. Fuera de Rayito no hay pasarela de secretos: la
credencial del modelo la pone la plataforma.
AsyncAgentProject(name: str, runtime: str | AgentRuntime, spec: AgentSpec, gateways: Mapping[str, SecretGateway] = dict(), source: str | None = None, exclude: Sequence[str] = (), requirements: str | None = None, limits: AgentLimits = AgentLimits(), serve: ServeOptions = ServeOptions(), allow_internet_access: bool = False, egress: Sequence[str] | None = None, memory_mib: int = AGENT_MIN_MEMORY_MIB, base: str = DEFAULT_AGENT_TEMPLATE_BASE, template: str | None = None, base_dir: str = '.', scaling: ScalingOptions = ScalingOptions(), env: Mapping[str, str] = dict(), network: NetworkPolicy | None = None, region: str | None = None, bucket: str | None = None, base_image_version: str | None = None, language: str | None = None, framework: str | None = None, versions: RuntimeVersions = RuntimeVersions(), graph: str | None = None, secret_env: Mapping[str, SecretEnvValue] = dict(), secret_env_from: Sequence[SecretEnvSource] = (), gateway_presets: Mapping[str, str] = dict())
dataclass
¶
Bases: AgentProject
AgentProject con las operaciones async: el mismo constructor y la
misma superficie (build, run, deploy, export) como corrutinas.
deploy(*, region: str | None = None, session: Any = None, access_token: str | None = None, keep_on_failure: bool = False) -> AsyncAgentDeployment
async
¶
Como AgentProject.deploy(), con AsyncAgentDeployment. Mismo
bloque de coste: crea un sandbox que vive hasta stop() o hasta
serve.timeout_seconds.
Coste y activación¶
Activa: await deploy() (o rayito agent deploy); nada más lo crea.
Recursos y llamadas AWS: un sandbox (run-microvm) que vive hasta
serve.timeout_seconds (como mucho 8 horas) o hasta
await AsyncAgentDeployment.stop(), y el token del proxy
(CreateMicrovmAuthToken, gratuito); el modelo lo llama la
pasarela del sandbox.
Coste aproximado: el del MicroVM por segundo mientras vive (2 GB:
≈ $0,14 por hora en us-east-1, consultado 2026-10-06 en
https://aws.amazon.com/lambda/pricing/) más el del modelo.
IAM: los de AsyncSandbox.create() y, por cada pasarela,
secretsmanager:GetSecretValue.
Cómo apagarla: await deployment.stop(); no llames a deploy() y
nada se crea.
Ejemplo:
deployment = await AsyncAgentProject.load("./support-bot").deploy()
(await deployment.invoke("Resume el README.")).text
await deployment.stop()
export(*, target: str = 'docker', out_dir: str | os.PathLike[str], overwrite: bool = False) -> AgentExport
async
¶
Como AgentProject.export(); la escritura de ficheros corre en un
hilo para no bloquear el bucle de eventos.
ServeOptions(port: int = AGENT_SERVICE_PORT, timeout_seconds: float = DEFAULT_AGENT_DEPLOY_TIMEOUT_SECONDS, idle: IdlePolicy | None = DEFAULT_IDLE_POLICY, max_concurrency: int = AGENT_SERVICE_MAX_CONCURRENCY, metadata: Mapping[str, str] = dict(), queue_max: int = AGENT_SERVICE_QUEUE_MAX_DEFAULT, queue_timeout_seconds: float = AGENT_SERVICE_QUEUE_TIMEOUT_SECONDS_DEFAULT)
dataclass
¶
Cómo se sirve el agente (AgentProject.deploy()): el port del
servicio (no 8080 ni 9000, que son de rayd), la vida del sandbox
(timeout_seconds, como mucho el máximo de la plataforma), la política
de idle (suspensión y reanudación automáticas; None la quita), la
concurrencia por VM (max_concurrency, acotada por las conexiones que
admite el MicroVM de AgentProject.memory_mib), las etiquetas metadata
del sandbox y la cola del host: queue_max llamadas esperan hasta
queue_timeout_seconds cuando el VM está lleno (con queue_max=0, el
valor por defecto, la llamada que no cabe recibe 429 enseguida).
AgentExport(path: str, files: tuple[str, ...], port: int, platform: str = EXPORT_PLATFORM)
dataclass
¶
Lo que export() escribió: el directorio, los ficheros (rutas
relativas, ordenadas), el puerto en el que sirve el contenedor y su
plataforma.
AgentDeployment(sandbox: Any, *, port: int, project: str | None = None, raw: bool = False, request_timeout: float = DEFAULT_DEPLOYMENT_REQUEST_TIMEOUT_SECONDS, transport_factory: Any = default_transport)
¶
Un agente servido desde un MicroVM (AgentProject.deploy()).
url y headers son lo que necesita cualquier cliente HTTP: las
cabeceras llevan el JWE del proxy de AWS y se leen frescas en cada
acceso (el token vive 60 minutos y el SDK lo renueva). invoke() y
stream() hablan rayito.agent-service/1; status() lee GET /ping;
stop() termina el sandbox. Un despliegue vive como mucho el timeout
del sandbox (8 horas como máximo): para más tiempo, vuelve a llamar a
deploy() y reconecta con AgentDeployment.connect(sandbox_id).
Coste y activación¶
Activa: crear el cliente (connect() o el valor de deploy()) no llama
a nadie; cada invoke(), stream() o status() es una petición
HTTP a tu sandbox.
Recursos y llamadas AWS: ninguno nuevo; el sandbox ya lo creó deploy().
Un sandbox suspendido se reanuda con la primera petición (factura
cómputo, como cualquier reanudación) y el modelo lo paga la pasarela
del sandbox, no este cliente.
Coste aproximado: el del sandbox mientras vive, más el del modelo (ver
AgentProject.deploy()).
IAM: GetMicrovm y CreateMicrovmAuthToken para connect() y para el
token del proxy; nada más.
Cómo apagarla: stop() termina el sandbox y con él el despliegue;
pause() deja de facturar cómputo sin perder el servicio.
Ejemplo:
deployment = AgentDeployment.connect(sandbox_id)
deployment.invoke("Resume el README.").text
deployment.stop()
access_token: str
property
¶
El access token del sandbox del despliegue. Con el que pasaste a
deploy(access_token=...) o, si no pasaste ninguno, el que se generó:
guárdalo (nunca lo imprimas ni lo versiones) para reconectarte desde
otro proceso con AgentDeployment.connect(sandbox_id, access_token=...)
o con rayito agent invoke --token-file.
connect(sandbox_id: str, **sandbox_options: Any) -> Self
classmethod
¶
Reconstruye el cliente de un despliegue desde las etiquetas de su
sandbox, en cualquier proceso. sandbox_options son los de
Sandbox.connect (region, session...).
invoke(prompt: str | None = None, session_id: str | None = None, model: str | None = None, reasoning: bool = False, *, input: Mapping[str, Any] | None = None) -> AgentResult
¶
Una invocación sin streaming: el AgentResult, o AgentException
si el agente falló (busy con el cupo lleno). Con input (un objeto
JSON, en lugar de prompt) se invoca un grafo con esquema de entrada
propio y result.output trae su salida.
stream(prompt: str | None = None, session_id: str | None = None, model: str | None = None, reasoning: bool = False, *, input: Mapping[str, Any] | None = None) -> AgentDeploymentStream
¶
Como invoke(), pero con los eventos a medida que llegan:
with deployment.stream("hola") as events: for event in events.
status() -> DeploymentStatus
¶
GET /ping: healthy, busy o unavailable.
pause(*, wait: bool = True) -> bool
¶
Suspende el sandbox del despliegue (Sandbox.pause()): mientras
duerme no factura cómputo y el servicio conserva su estado. False
si ya estaba suspendido. La siguiente petición (o resume()) lo
reanuda; con idle (activo por defecto) también se suspende solo.
resume(*, wait: bool = True) -> None
¶
Reanuda el sandbox suspendido (Sandbox.resume()) y, con wait,
espera a que esté listo. No hace falta antes de invoke(): una
petición a un sandbox suspendido ya lo reanuda.
set_timeout(timeout: int) -> None
¶
Fija la vida restante del sandbox del despliegue
(Sandbox.set_timeout, segundos enteros): rayd lo termina solo al
vencer. Una flota lo usa para que un VM sobrante desaparezca sin
servidor propio.
refresh_gateways() -> None
¶
Vuelve a mandar las pasarelas del sandbox (sbx.gateways.refresh()):
releen de Secrets Manager el valor actual de cada secreto. Una flota lo
usa tras renovar una clave (renew_gateway_keys).
stop() -> None
¶
Termina el sandbox del despliegue. Idempotente.
AgentDeploymentStream(response: DeploymentResponse)
¶
Iterable de AgentEvent sobre la respuesta SSE de una invocación. El
último evento es Done o AgentFailed; nunca lanza por un fallo del
agente (result() sí).
result() -> AgentResult
¶
Consume lo que falte y devuelve el AgentResult; si el agente
falló lanza AgentException.
AsyncAgentDeployment(sandbox: Any, *, port: int, host_access: HostAccess, project: str | None = None, raw: bool = False, request_timeout: float = DEFAULT_DEPLOYMENT_REQUEST_TIMEOUT_SECONDS, transport_factory: Any = default_async_transport)
¶
El espejo asíncrono de AgentDeployment: las mismas operaciones como
corrutinas (invoke, status, stop, connect), stream() como
contexto asíncrono y url/headers como propiedades.
Coste y activación¶
Activa: crear el cliente (connect() o el valor de deploy()) no llama
a nadie salvo a GetMicrovm y CreateMicrovmAuthToken para el token
del proxy; cada invoke(), stream() o status() es una petición
HTTP a tu sandbox.
Recursos y llamadas AWS: ninguno nuevo; el sandbox ya lo creó deploy().
Un sandbox suspendido se reanuda con la primera petición (factura
cómputo, como cualquier reanudación) y el modelo lo paga la pasarela
del sandbox, no este cliente.
Coste aproximado: el del sandbox mientras vive, más el del modelo (ver
AsyncAgentProject.deploy()).
IAM: GetMicrovm y CreateMicrovmAuthToken; nada más.
Cómo apagarla: await stop() termina el sandbox y con él el despliegue;
await pause() deja de facturar cómputo sin perder el servicio.
Ejemplo:
deployment = await AsyncAgentDeployment.connect(sandbox_id)
(await deployment.invoke("Resume el README.")).text
await deployment.stop()
access_token: str
property
¶
El access token del sandbox del despliegue. Con el que pasaste a
deploy(access_token=...) o, si no pasaste ninguno, el que se generó:
guárdalo (nunca lo imprimas ni lo versiones) para reconectarte desde
otro proceso con AsyncAgentDeployment.connect(sandbox_id, access_token=...)
o con rayito agent invoke --token-file.
connect(sandbox_id: str, **sandbox_options: Any) -> Self
async
classmethod
¶
Reconstruye el cliente de un despliegue desde las etiquetas de su
sandbox, en cualquier proceso. sandbox_options son los de
AsyncSandbox.connect (region, session...).
invoke(prompt: str | None = None, session_id: str | None = None, model: str | None = None, reasoning: bool = False, *, input: Mapping[str, Any] | None = None) -> AgentResult
async
¶
Una invocación sin streaming: el AgentResult, o AgentException
si el agente falló (busy con el cupo lleno). Con input (un objeto
JSON, en lugar de prompt) se invoca un grafo con esquema de entrada
propio y result.output trae su salida.
stream(prompt: str | None = None, session_id: str | None = None, model: str | None = None, reasoning: bool = False, *, input: Mapping[str, Any] | None = None) -> AsyncAgentDeploymentStream
¶
Como invoke(), pero con los eventos a medida que llegan:
async with deployment.stream("hola") as events: async for event in
events.
status() -> DeploymentStatus
async
¶
GET /ping: healthy, busy o unavailable.
pause(*, wait: bool = True) -> bool
async
¶
Suspende el sandbox del despliegue (AsyncSandbox.pause()):
mientras duerme no factura cómputo y el servicio conserva su estado.
False si ya estaba suspendido. La siguiente petición (o resume())
lo reanuda; con idle (activo por defecto) también se suspende solo.
resume(*, wait: bool = True) -> None
async
¶
Reanuda el sandbox suspendido (AsyncSandbox.resume()) y, con
wait, espera a que esté listo. No hace falta antes de invoke():
una petición a un sandbox suspendido ya lo reanuda.
set_timeout(timeout: int) -> None
async
¶
Fija la vida restante del sandbox del despliegue
(AsyncSandbox.set_timeout, segundos enteros): rayd lo termina
solo al vencer. Una flota lo usa para que un VM sobrante desaparezca
sin servidor propio.
refresh_gateways() -> None
async
¶
Como AgentDeployment.refresh_gateways(): vuelve a mandar las
pasarelas del sandbox (sbx.gateways.arefresh()).
stop() -> None
async
¶
Termina el sandbox del despliegue. Idempotente.
AsyncAgentDeploymentStream(open_response: Callable[[], Awaitable[AsyncDeploymentResponse]])
¶
Iterable asíncrono de AgentEvent: async with deployment.stream(...)
as events: async for event in events. La petición se hace al entrar. El
último evento es Done o AgentFailed; nunca lanza por un fallo del
agente (result() sí).
result() -> AgentResult
async
¶
Consume lo que falte y devuelve el AgentResult; si el agente
falló lanza AgentException.
DeploymentStatus(state: DeploymentState, ready: bool, busy: bool, port: int, project: str | None)
dataclass
¶
El estado de un despliegue según GET /ping: healthy (listo),
busy (con el cupo de ejecuciones lleno) o unavailable (el host no
contesta o aún no está listo).
Zero-config deploy and fleets¶
deploy_agent() detects an agent project you already have, deploys it and returns an AgentFleet: several MicroVMs of the same image with the sessions spread across them (Deploy your agent, Several sessions and several VMs). They cost (images and MicroVMs) and do nothing until you call them; plan_deploy() and AgentProject.detect() make no AWS call.
deploy_agent(path: str | os.PathLike[str] = '.', *, project: AgentProject | None = None, options: AgentDeployOptions | None = None, overrides: DetectOverrides | None = None, region: str | None = None, session: Any = None, target: Literal['microvm', 'agentcore'] = 'microvm', agentcore: AgentCoreOptions | None = None) -> AgentFleet | AgentCoreFleet
¶
deploy_agent(
path: str | os.PathLike[str] = ...,
*,
project: AgentProject | None = ...,
options: AgentDeployOptions | None = ...,
overrides: DetectOverrides | None = ...,
region: str | None = ...,
session: Any = ...,
target: Literal["microvm"] = ...,
agentcore: None = ...,
) -> AgentFleet
deploy_agent(
path: str | os.PathLike[str] = ...,
*,
project: AgentProject | None = ...,
options: AgentDeployOptions | None = ...,
overrides: DetectOverrides | None = ...,
region: str | None = ...,
session: Any = ...,
target: Literal["agentcore"],
agentcore: AgentCoreOptions | None = ...,
) -> AgentCoreFleet
Despliega el agente de path y devuelve su AgentFleet; con
target="agentcore", su AgentCoreFleet.
path es un directorio con el proyecto (con o sin rayito-agent.toml):
el lenguaje, el framework, el punto de entrada y la instalación se
detectan de sus ficheros sin ejecutar su código, y todo lo detectado se
puede fijar con overrides o con el fichero. Un project explícito se
usa tal cual. options (AgentDeployOptions) dice dónde y cómo; region y
session son los de boto3.
El orden de cada valor es argumento explícito, fichero de proyecto,
variable de entorno y descubrimiento; ninguno crea nada en silencio:
Rayito no crea buckets, un secreto sólo se crea con
create_secret_from_env=True y una imagen base ausente sólo se publica si
pasas base_publisher. La imagen del agente se construye sólo si cambió su
contenido. El access token de la flota es options.access_token, o
RAYITO_ACCESS_TOKEN, o uno nuevo en AgentFleet.access_token.
Con target="agentcore" (y agentcore=AgentCoreOptions(...) para los
modelos y secretos del rol, los plazos de sesión y las etiquetas) el agente
se despliega en Amazon Bedrock AgentCore Runtime sin Docker local: una
pila de CloudFormation por agente (rayito-agentcore-<nombre>), la imagen
arm64 construida en CodeBuild sólo si cambió el contenido y un runtime
creado o actualizado por nombre, con MMDSv2 exigido. No hay pasarela de
secretos: el agente lee las credenciales del rol del runtime, que sólo
puede invocar los modelos y leer los secretos que le des. Las opciones de
MicroVMs que AgentCore no admite (scaling, secret_names,
access_token...) son AgentCoreException con código
option_not_supported.
Coste y activación¶
Activa: llamar a deploy_agent() (o rayito agent deploy); nada más lo
crea. plan_deploy() (--dry-run) calcula el coste sin llamar a AWS.
Con target="agentcore", sólo ese argumento crea nada de AgentCore,
CodeBuild o ECR; sin él no se crea ni se carga ningún cliente de esos
servicios.
Recursos y llamadas AWS: min_vms MicroVMs (run-microvm) y
warm_vms plazas aparcadas; una versión de imagen nueva si cambió el
contenido (create/update-microvm-image, un objeto en S3);
GetCallerIdentity, HeadBucket, GetMicrovmImage y
DescribeSecret de lectura; con create_secret_from_env=True,
CreateSecret; con base_publisher, una imagen base; con
session_index, DynamoDB; tras arrancar la flota, la receta en
Parameter Store (PutParameter de un SecureString estándar, salvo
con save_recipe=False); con renew_gateway_keys, DescribeSecret
y PutSecretValue sobre el secreto de cada pasarela bedrock.
Con target="agentcore": la pila
rayito-agentcore-<nombre> (repositorio de ECR, proyecto de CodeBuild
con su grupo de logs y dos roles), un zip del contexto de build en el
bucket de artefactos mientras dura el build, un build de CodeBuild si
cambió el contenido, y un runtime de AgentCore (CreateAgentRuntime
y UpdateAgentRuntime); de lectura, GetCallerIdentity, HeadBucket,
DescribeStacks, DescribeImages, ListAgentRuntimes y
GetAgentRuntime.
Coste aproximado: por VM, el del MicroVM mientras vive (2 GB: ≈ $0,13 por
hora en us-east-1, consultado 2026-10-06 en
https://aws.amazon.com/lambda/pricing/); la imagen nueva, ≈ 3,0 GB de
snapshot (≈ $0,011 de escritura y ≈ $0,056 por semana mínima de
almacenamiento); un secreto, $0,40 al mes
(https://aws.amazon.com/secrets-manager/pricing/, consultado
2026-09-30); el modelo lo cobra su proveedor. Con
target="agentcore" (us-east-1, consultado 2026-10-19): CodeBuild
arm1.small $0,0034 por minuto de build (100 minutos gratis al mes,
https://aws.amazon.com/codebuild/pricing/), imágenes en ECR $0,10 por
GB-mes, logs $0,50 por GB ingerido
(https://aws.amazon.com/cloudwatch/pricing/) y el runtime, V1,
$0,0895 por vCPU-hora y $0,00945 por GB-hora de uso real
(https://aws.amazon.com/bedrock/agentcore/pricing/); sin sesiones no
hay cómputo.
IAM: los de Sandbox.create(), Sandbox.list() y AgentTemplate.build()
(RayitoSandboxRunner, RayitoTemplateBuilder),
secretsmanager:DescribeSecret y, con create_secret_from_env,
secretsmanager:CreateSecret, sts:GetCallerIdentity y
s3:ListBucket sobre el bucket del artefacto; ssm:PutParameter
sobre parameter/rayito/agents/* para la receta (sin él, un aviso
recipe_access_denied y el despliegue sigue); con
renew_gateway_keys, secretsmanager:PutSecretValue y
bedrock:CallWithBearerToken. Con
target="agentcore": CloudFormation sobre rayito-agentcore-* con
CAPABILITY_IAM, ECR, CodeBuild, S3 sobre
rayito/images/agentcore/*, AgentCore (CreateAgentRuntime,
UpdateAgentRuntime, GetAgentRuntime, ListAgentRuntimes) e
iam:PassRole del rol del runtime.
Cómo apagarla: AgentFleet.stop() termina los VMs (y borra la
receta); los valores por defecto de AgentDeployOptions no crean
ningún secreto, imagen base ni índice; save_recipe=False no guarda
la receta; sin llamar a deploy_agent() nada se crea. Un agente
de AgentCore se borra con AgentCoreFleet.delete() (rayito agent
delete --target agentcore).
Ejemplo:
options = AgentDeployOptions(bucket="amzn-s3-demo-bucket")
fleet = deploy_agent("./mi-agente", options=options)
fleet.invoke("Resume el README.").text
fleet.stop()
deploy_agent_async(path: str | os.PathLike[str] = '.', *, project: AgentProject | None = None, options: AgentDeployOptions | None = None, overrides: DetectOverrides | None = None, region: str | None = None, session: Any = None, target: Literal['microvm', 'agentcore'] = 'microvm', agentcore: AgentCoreOptions | None = None) -> AsyncAgentFleet | AsyncAgentCoreFleet
async
¶
deploy_agent_async(
path: str | os.PathLike[str] = ...,
*,
project: AgentProject | None = ...,
options: AgentDeployOptions | None = ...,
overrides: DetectOverrides | None = ...,
region: str | None = ...,
session: Any = ...,
target: Literal["microvm"] = ...,
agentcore: None = ...,
) -> AsyncAgentFleet
deploy_agent_async(
path: str | os.PathLike[str] = ...,
*,
project: AgentProject | None = ...,
options: AgentDeployOptions | None = ...,
overrides: DetectOverrides | None = ...,
region: str | None = ...,
session: Any = ...,
target: Literal["agentcore"],
agentcore: AgentCoreOptions | None = ...,
) -> AsyncAgentCoreFleet
Como deploy_agent(), con AsyncAgentFleet (o AsyncAgentCoreFleet
con target="agentcore"): mismas opciones, mismo orden de resolución y
mismo coste. Las lecturas de AWS previas a crear nada corren en un hilo
para no bloquear el bucle de eventos.
Coste y activación¶
Activa: await deploy_agent_async(); nada más lo crea.
Recursos y llamadas AWS: los de deploy_agent().
Coste aproximado: el de deploy_agent(), por VM (2 GB: ≈ $0,13 por hora en
us-east-1, consultado 2026-10-06 en https://aws.amazon.com/lambda/pricing/);
con target="agentcore", el de AgentCore (V1: $0,0895 por vCPU-hora y
$0,00945 por GB-hora de uso real, us-east-1, consultado 2026-10-19 en
https://aws.amazon.com/bedrock/agentcore/pricing/) más CodeBuild, ECR y
logs como se detalla en deploy_agent().
IAM: los de deploy_agent().
Cómo apagarla: await fleet.stop() (en AgentCore, await fleet.delete());
sin llamar a esta función nada se crea.
Ejemplo:
fleet = await deploy_agent_async("./mi-agente")
(await fleet.invoke("Resume el README.")).text
await fleet.stop()
plan_deploy(path: str | os.PathLike[str] = '.', *, project: AgentProject | None = None, options: AgentDeployOptions | None = None, overrides: DetectOverrides | None = None, region: str | None = None, session: Any = None, target: Literal['microvm', 'agentcore'] = 'microvm', agentcore: AgentCoreOptions | None = None) -> AgentDeployPlan | AgentCoreDeployPlan
¶
plan_deploy(
path: str | os.PathLike[str] = ...,
*,
project: AgentProject | None = ...,
options: AgentDeployOptions | None = ...,
overrides: DetectOverrides | None = ...,
region: str | None = ...,
session: Any = ...,
target: Literal["microvm"] = ...,
agentcore: None = ...,
) -> AgentDeployPlan
plan_deploy(
path: str | os.PathLike[str] = ...,
*,
project: AgentProject | None = ...,
options: AgentDeployOptions | None = ...,
overrides: DetectOverrides | None = ...,
region: str | None = ...,
session: Any = ...,
target: Literal["agentcore"],
agentcore: AgentCoreOptions | None = ...,
) -> AgentCoreDeployPlan
Lo que deploy_agent() haría con estos argumentos, sin llamar a AWS:
detecta el proyecto (lee ficheros locales, no ejecuta su código), y calcula
el escalado, el origen de cada valor y el coste de lista. Con
target="agentcore" devuelve un AgentCoreDeployPlan: valida las opciones,
deriva los nombres de los recursos y dice qué rol tendrá el runtime y qué
cuesta; agentcore= sólo vale con ese destino.
Coste y activación¶
Activa: llamar a plan_deploy() (o rayito agent deploy --dry-run).
Recursos y llamadas AWS: ninguno; no crea clientes de AWS ni carga
ningún paquete opcional.
Coste aproximado: ninguno.
IAM: ninguna.
Cómo apagarla: no la llamo.
Ejemplo:
plan = plan_deploy("./mi-agente")
plan.cost.running_usd_per_hour
AgentDeployOptions(bucket: str | None = None, base_image_version: str | None = None, secret_names: Mapping[str, str] = dict(), create_secret_from_env: bool = False, ensure_base_image: bool = True, base_publisher: Callable[[], None] | None = None, access_token: str | None = None, keep_on_failure: bool = False, build_image: bool | None = None, scaling: ScalingOptions | None = None, session_index: DynamoDbIndex | None = None, pool_backend: PoolBackend | None = None, on_build_logs: Callable[[str], None] | None = None, on_step: Callable[[AgentDeployStep], None] | None = None, build_timeout_seconds: float = DEFAULT_BUILD_TIMEOUT_SECONDS, warm_timeout_seconds: float = AGENT_FLEET_WARM_READY_TIMEOUT_SECONDS, create_secrets_from: str | None = None, check_env: bool = False, save_recipe: bool = True, scale_in_after_seconds: float | None = None, renew_gateway_keys: bool = False)
dataclass
¶
Dónde y cómo se despliega (los argumentos de deploy_agent() que no
describen al agente): bucket del artefacto de la imagen,
base_image_version (None = la más reciente de la base), secret_names
(pasarela → nombre de un secreto que ya existe), create_secret_from_env
(crea el que falte desde la variable estándar del proveedor),
ensure_base_image y base_publisher (quién publica la base si falta),
access_token, keep_on_failure, build_image (None = construir si hay
bucket; True = siempre; False = reutilizar la imagen existente),
scaling (gana al del proyecto), session_index (índice de sesiones de
los VMs dedicados), pool_backend (plazas calientes que sobreviven al
proceso), on_build_logs, on_step (recibe cada AgentDeployStep),
build_timeout_seconds y warm_timeout_seconds (espera a que las plazas calientes queden
aparcadas), create_secrets_from (un .env cuyos valores van a un secreto JSON
rayito/agents/<nombre>/env que el agente recibe como secret_env_from) y check_env
(avisa de las variables de .env.example que no reciben valor).
save_recipe (por defecto True) guarda la receta de la flota en
Parameter Store tras arrancarla, para que AgentFleet.connect(nombre)
cree VMs iguales desde otro proceso; scale_in_after_seconds fija tras
cuántos segundos sin uso se termina un VM por encima de min_vms, y
renew_gateway_keys (por defecto False) renueva la clave de corta
duración de Bedrock de las pasarelas bedrock antes de crear cada VM.
Coste y activación¶
Activa: nada por sí mismo; el valor es puro. deploy_agent() es lo que
cuesta: create_secret_from_env=True crea un secreto,
create_secrets_from crea o actualiza el secreto de un .env
(CreateSecret o PutSecretValue, $0,40 al mes por secreto),
base_publisher una imagen base, session_index filas de DynamoDB.
save_recipe=True (por defecto, la única excepción de ADR-034)
guarda un parámetro SecureString estándar; renew_gateway_keys
escribe la clave en el secreto de la pasarela.
Recursos y llamadas AWS: ninguno aquí. Con save_recipe, un
PutParameter tras arrancar la flota (ver SsmRecipeStore); con
renew_gateway_keys, DescribeSecret y PutSecretValue (ver
GatewayKeyRenewer).
Coste aproximado: ninguno aquí; ver deploy_agent(). La receta: el
parámetro estándar no tiene cargo y su petición de KMS entra en las
20 000 gratuitas al mes (después $0,03 por 10 000;
https://aws.amazon.com/kms/pricing/, consultado 2026-10-22).
IAM: ninguna para este valor. Guardar la receta: ssm:PutParameter
sobre parameter/rayito/agents/*.
Cómo apagarla: los valores por defecto no crean ningún secreto, imagen
base ni índice; check_env sólo lee ficheros locales;
save_recipe=False (--no-save-recipe) no guarda la receta.
Ejemplo:
AgentDeployOptions(bucket="amzn-s3-demo-bucket", secret_names={"bedrock": "mi-clave"})
AgentDeployPlan(name: str, template: str, base: str, memory_mib: int, region: str | None, scaling: ScalingOptions, bucket_source: str, build_image: bool | None, secrets: tuple[AgentPlannedSecret, ...], token_source: str, cost: AgentDeployCostEstimate, notes: tuple[str, ...], detection: object | None = None, recipe: RecipePlan = RECIPE_PLAN_SAVE)
dataclass
¶
Lo que deploy_agent() haría, calculado sin llamar a AWS: el agente,
el escalado, la región (la del entorno, si la hay), de dónde saldrá el
bucket, la imagen base, los secretos, el coste y las notas.
AgentDeployStep(kind: str, detail: str)
dataclass
¶
Un paso de deploy_agent() que ya ocurrió: kind es de una lista
cerrada (base_image, secret_created, bucket, image, fleet,
warm, recipe) y detail un dato corto para mostrar (la pasarela, el
origen y el bucket, la versión de la imagen, el código del aviso de una
receta que no se guardó); nunca el valor ni el nombre de un secreto. Con
target="agentcore", kind es la clave de la línea de progreso
(stackDeploy, buildStart, runtimeReady...) y detail la línea ya
escrita.
AgentDeployCostEstimate(running_usd_per_hour: float, parked_usd_per_day: float, image_build_usd: float, image_storage_usd_per_week: float)
dataclass
¶
Lo que cuesta lo que deploy_agent() crea, en dólares, a precios de
lista (limits.json): running_usd_per_hour por los VMs min_vms
mientras viven, parked_usd_per_day por las plazas aparcadas (sólo
almacenamiento de snapshot), image_build_usd por una versión nueva de la
imagen y image_storage_usd_per_week por conservarla (mínimo una
semana). No incluye los tokens del modelo.
ScalingOptions(min_vms: int = AGENT_SCALING_MIN_VMS_DEFAULT, max_vms: int = AGENT_SCALING_MAX_VMS_DEFAULT, warm_vms: int = AGENT_SCALING_WARM_VMS_DEFAULT, sessions: SessionMode = DEFAULT_SESSION_MODE, scale_in_after_seconds: float = AGENT_SCALE_IN_AFTER_SECONDS_DEFAULT)
dataclass
¶
Cuántos MicroVMs sirven el agente y cómo se reparten las sesiones.
min_vms corren siempre, warm_vms esperan suspendidos (una sesión nueva
los reanuda en vez de crear un VM) y max_vms acota el total; con
sessions="dedicated" cada sesión tiene su propio MicroVM. Los VMs por
encima de min_vms se terminan tras scale_in_after_seconds sin uso.
Los valores por defecto son los de un solo VM: nada cambia para quien no
pasa ScalingOptions.
Coste y activación¶
Activa: deploy_agent() (rayito agent deploy) con max_vms mayor que 1,
o con warm_vms mayor que 0; por sí sola, esta clase no crea nada.
Recursos y llamadas AWS: min_vms MicroVMs en marcha (run-microvm),
warm_vms plazas suspendidas de un pool y los VMs extra que cree el
reparto hasta max_vms.
Coste aproximado: el del MicroVM por segundo mientras vive (2 GB: ≈ $0,126
por hora en us-east-1, consultado 2026-10-06 en
https://aws.amazon.com/lambda/pricing/), por cada VM; una plaza
aparcada o un VM suspendido sólo pagan el almacenamiento de su
snapshot.
IAM: los de Sandbox.create(), Sandbox.list() y Sandbox.connect().
Cómo apagarla: los valores por defecto (min_vms=1, max_vms=1, warm_vms=0)
son un solo VM; fleet.stop() termina todos los VMs.
Ejemplo:
ScalingOptions(min_vms=1, max_vms=3, warm_vms=1)
routes_by_handle: bool
property
¶
Con más de un VM posible, AgentResult.session_id es un asa que
nombra el VM (rs1.<sandbox_id>.<session_id>); con uno solo, el id
de sesión queda como siempre.
DetectOverrides(framework: str | None = None, language: str | None = None, entrypoint: str | None = None, protocol: str | None = None, model_id: str | None = None, model_provider: str | None = None, model_base_url: str | None = None, graph: str | None = None)
dataclass
¶
Lo que el usuario fuerza por encima de la detección (--framework,
--language, --entry, --protocol, --model-id, --model-provider,
--model-base-url, --graph). entrypoint="http" sirve la app HTTP del
proyecto en vez del framework del agente. model_provider es un preset de
pasarela (openai-compatible, litellm...) y model_base_url la URL
https de la pasarela de LLM, que pasa a ser su upstream. graph
elige un grafo de langgraph.json por su nombre.
AgentFleet(project: AgentProject | None, *, name: str | None = None, access_token: str | None = None, scaling: ScalingOptions | None = None, service: ProjectService | None = None, directory: Any = None, pool_factory: Callable[..., SandboxPool] | None = None, pool_backend: PoolBackend | None = None, session_index: DynamoDbIndex | None = None, keep_on_failure: bool = False, region: str | None = None, session: Any = None, transport_factory: Any = default_transport, clock: Callable[[], float] = time.monotonic, sleep: Callable[[float], None] = time.sleep, renew_gateway_keys: bool = False, recipe: FleetRecipe | None = None, recipe_store: FleetRecipeStore | None = None, key_renewer: GatewayKeyRenewer | None = None)
¶
Un agente servido por uno o varios MicroVMs (deploy_agent()).
invoke() y stream() colocan cada sesión nueva en un VM con cupo (con
ScalingOptions.sessions="dedicated", uno por sesión), crean uno si hace
falta y cabe, y esperan en una cola cliente hasta
ServeOptions.queue_timeout_seconds si la flota está llena
(CapacityException con code="agent_capacity" al agotarse). Con más de
un VM posible (max_vms > 1), el session_id del resultado es un handle
rs1.<sandbox>.<sesión>: al volver a pasarlo, la llamada va derecha a ese
VM; si el VM ya no existe, SandboxException con code="agent_vm_lost".
Con max_vms == 1 el id de sesión no cambia.
Un id de sesión elegido por el llamante no dice en qué VM está. Con un
VM (o shared y un solo proceso) no importa; con dedicated, sólo el
mismo proceso lo recuerda, salvo con session_index=DynamoDbIndex(...),
que escribe una fila por VM dedicado para encontrarlo desde cualquier
proceso. Sin índice, un id desconocido empieza un VM nuevo y el resultado
trae el handle con el que seguir.
Los VMs de la flota son todos los MicroVMs no terminados de la imagen del
proyecto (un MicroVM no se puede etiquetar): una imagen, una flota. Los
VMs por encima de min_vms se terminan solos tras
scale_in_after_seconds sin uso (set_timeout de rayd, sin servidor
propio).
Coste y activación¶
Activa: deploy_agent() (rayito agent deploy) crea min_vms VMs y
warm_vms plazas aparcadas; invoke() crea más, hasta max_vms, si
las sesiones llenan los que hay. Construir o reconectar la flota no
crea nada.
Recursos y llamadas AWS: un MicroVM por VM (run-microvm), el token del
proxy (CreateMicrovmAuthToken, gratuito) y list-microvms al
reconectar; con warm_vms, plazas suspendidas del pool; con
session_index, una fila de DynamoDB por VM dedicado.
Coste aproximado: el del MicroVM por segundo mientras vive (2 GB:
≈ $0,14 por hora en us-east-1, consultado 2026-10-06 en
https://aws.amazon.com/lambda/pricing/), por cada VM; una plaza
aparcada no factura cómputo pero sí almacenamiento de snapshot.
IAM: los de Sandbox.create(), Sandbox.list() y Sandbox.connect()
(RayitoSandboxRunner) y secretsmanager:GetSecretValue por
pasarela; con session_index, los de DynamoDbIndex. Leer y borrar
la receta (connect(nombre) sin project, stop()), los de
SsmRecipeStore; con renew_gateway_keys, los de
GatewayKeyRenewer.
Cómo apagarla: stop() termina todos los VMs; min_vms=1, max_vms=1,
warm_vms=0 (por defecto) es un solo VM; sin llamar a
deploy_agent() nada se crea. connect(..., use_recipe=False) no
lee la receta y stop(keep_recipe=True) no la borra;
renew_gateway_keys=False (por defecto) no renueva ninguna clave.
Ejemplo:
fleet = deploy_agent("./mi-agente")
fleet.invoke("Resume el README.").text
fleet.stop()
access_token: str
property
¶
El access token de todos los VMs de la flota: guárdalo (nunca lo
imprimas ni lo versiones) para AgentFleet.connect() desde otro
proceso. Una flota reconectada sin token (para listarla o terminarla)
no lo tiene: InvalidArgumentException.
deployments: tuple[AgentDeployment, ...]
property
¶
Los clientes de los VMs que este proceso ya abrió.
connect(name: str, *, access_token: str | None = None, project: AgentProject | None = None, scaling: ScalingOptions | None = None, region: str | None = None, session: Any = None, use_recipe: bool = True, renew_gateway_keys: bool | None = None, **dependencies: Any) -> Self
classmethod
¶
Reconstruye la flota de la imagen name en cualquier proceso: todos
sus MicroVMs no terminados, sin reanudar ninguno (un VM se abre al
usarlo).
Sin project y con use_recipe (por defecto) lee la receta que
guardó deploy_agent() (un GetParameter): con ella la flota crea
VMs iguales a los del despliegue (proyecto tras las banderas, versión
de la imagen y escalado) y status() da su escalado real. Un
scaling= explícito gana a la receta. Las claves de Bedrock sólo se
renuevan con renew_gateway_keys=True: si la receta lo pedía y no
lo pasas, la flota no renueva y avisa recipe_renewal_ignored. Sin
receta (o con project=, o use_recipe=False), la flota es la de
0.16: sin project enruta y consulta pero no puede crear VMs.
start() -> Self
¶
Crea min_vms VMs (todo o nada: si uno falla, termina los que
creó) y arranca el pool de plazas calientes. Lo llama
deploy_agent().
refresh_members() -> None
¶
Vuelve a leer qué VMs de la imagen siguen vivos (list-microvms):
añade los nuevos, olvida los que ya no están y deja fuera las plazas
aparcadas del pool de este proceso.
reconcile() -> None
¶
Deja la flota dentro de ScalingOptions: olvida los VMs perdidos,
crea los que falten hasta min_vms y termina los que sobren por
encima de max_vms (sólo los libres).
scale(*, min_vms: int | None = None, max_vms: int | None = None, warm_vms: int | None = None) -> None
¶
Cambia los límites de la flota (se validan como ScalingOptions) y
la reconcilia: crea hasta min_vms, termina los sobrantes y ajusta
las plazas calientes.
detach() -> None
¶
Para el relleno de plazas calientes de este proceso y deja los VMs
vivos: un proceso de un solo uso (rayito agent deploy) termina así
sin tirar lo que creó. Las plazas aparcadas requieren un backend de
pool persistente (pool_backend).
stop(*, keep_recipe: bool = False) -> None
¶
Termina todos los VMs de la flota y las plazas del pool y, si este
proceso guardó o leyó su receta, la borra (keep_recipe=True la
conserva). Sigue aunque uno falle y, al final, lanza el primer
error.
status() -> FleetStatus
¶
Estado de la flota: pregunta a los VMs que este proceso ya abrió
(GET /ping) y deja como unknown los demás.
wait_warm(timeout: float, poll: float) -> bool
¶
Espera a que las plazas calientes queden aparcadas; False si se
agota timeout (la flota funciona igual: las plazas son una
optimización de latencia).
invoke(prompt: str | None = None, session_id: str | None = None, model: str | None = None, reasoning: bool = False, *, input: Mapping[str, Any] | None = None) -> AgentResult
¶
Una invocación sin streaming: el AgentResult, con el id de sesión
enrutable si la flota puede tener varios VMs. Con input en lugar de
prompt, result.output trae la salida del grafo; se comprueba antes
de reservar un VM.
stream(prompt: str | None = None, session_id: str | None = None, model: str | None = None, reasoning: bool = False, *, input: Mapping[str, Any] | None = None) -> AgentFleetStream
¶
Como invoke(), con los eventos a medida que llegan. El VM queda
ocupado hasta cerrar el stream.
AsyncAgentFleet(project: AgentProject | None, *, name: str | None = None, access_token: str | None = None, scaling: ScalingOptions | None = None, service: AsyncProjectService | None = None, directory: Any = None, pool_factory: Callable[..., AsyncSandboxPool] | None = None, pool_backend: PoolBackend | None = None, session_index: DynamoDbIndex | None = None, keep_on_failure: bool = False, region: str | None = None, session: Any = None, transport_factory: Any = default_async_transport, clock: Callable[[], float] = time.monotonic, sleep: Callable[[float], Awaitable[None]] = asyncio.sleep, renew_gateway_keys: bool = False, recipe: FleetRecipe | None = None, recipe_store: FleetRecipeStore | None = None, key_renewer: GatewayKeyRenewer | None = None)
¶
El espejo asíncrono de AgentFleet: las mismas operaciones como
corrutinas (start, invoke, status, scale, reconcile, stop,
connect) y stream() como contexto asíncrono. Sesiones, id de sesión
enrutable (rs1.<sandbox>.<sesión>), cola cliente, sesiones dedicadas e
índice de sesión opcional son los de AgentFleet.
Coste y activación¶
Activa: await deploy_agent_async() crea min_vms VMs y warm_vms
plazas aparcadas; invoke() crea más, hasta max_vms, si las
sesiones llenan los que hay. Construir o reconectar la flota no crea
nada.
Recursos y llamadas AWS: un MicroVM por VM (run-microvm), el token del
proxy (CreateMicrovmAuthToken, gratuito) y list-microvms al
reconectar; con warm_vms, plazas suspendidas del pool; con
session_index, una fila de DynamoDB por VM dedicado.
Coste aproximado: el del MicroVM por segundo mientras vive (2 GB:
≈ $0,14 por hora en us-east-1, consultado 2026-10-06 en
https://aws.amazon.com/lambda/pricing/), por cada VM; una plaza
aparcada no factura cómputo pero sí almacenamiento de snapshot.
IAM: los de AsyncSandbox.create(), list() y connect()
(RayitoSandboxRunner) y secretsmanager:GetSecretValue por
pasarela; con session_index, los de DynamoDbIndex.
Cómo apagarla: await stop() termina todos los VMs; min_vms=1,
max_vms=1, warm_vms=0 (por defecto) es un solo VM; sin llamar a
deploy_agent_async() nada se crea.
Ejemplo:
fleet = await deploy_agent_async("./mi-agente")
(await fleet.invoke("Resume el README.")).text
await fleet.stop()
access_token: str
property
¶
El access token de todos los VMs de la flota: guárdalo (nunca lo
imprimas ni lo versiones) para AsyncAgentFleet.connect() desde otro
proceso. Una flota reconectada sin token (para listarla o terminarla)
no lo tiene: InvalidArgumentException.
deployments: tuple[AsyncAgentDeployment, ...]
property
¶
Los clientes de los VMs que este proceso ya abrió.
connect(name: str, *, access_token: str | None = None, project: AgentProject | None = None, scaling: ScalingOptions | None = None, region: str | None = None, session: Any = None, use_recipe: bool = True, renew_gateway_keys: bool | None = None, **dependencies: Any) -> Self
async
classmethod
¶
Como AgentFleet.connect(): sin project y con use_recipe lee
la receta de la flota (un GetParameter, en un hilo) y con ella crea
VMs iguales a los del despliegue; scaling= explícito gana a la
receta y las claves sólo se renuevan con renew_gateway_keys=True
(la receta nunca lo activa: recipe_renewal_ignored).
start() -> Self
async
¶
Crea min_vms VMs (todo o nada: si uno falla, termina los que
creó) y arranca el pool de plazas calientes. Lo llama
deploy_agent_async().
refresh_members() -> None
async
¶
Vuelve a leer qué VMs de la imagen siguen vivos (list-microvms):
añade los nuevos, olvida los que ya no están y deja fuera las plazas
aparcadas del pool de este proceso.
reconcile() -> None
async
¶
Deja la flota dentro de ScalingOptions: olvida los VMs perdidos,
crea los que falten hasta min_vms y termina los que sobren por
encima de max_vms (sólo los libres).
scale(*, min_vms: int | None = None, max_vms: int | None = None, warm_vms: int | None = None) -> None
async
¶
Cambia los límites de la flota (se validan como ScalingOptions) y
la reconcilia: crea hasta min_vms, termina los sobrantes y ajusta
las plazas calientes.
detach() -> None
async
¶
Para el relleno de plazas calientes de este proceso y deja los VMs
vivos: un proceso de un solo uso (rayito agent deploy) termina así
sin tirar lo que creó. Las plazas aparcadas requieren un backend de
pool persistente (pool_backend).
stop(*, keep_recipe: bool = False) -> None
async
¶
Termina todos los VMs de la flota y las plazas del pool y, si este
proceso guardó o leyó su receta, la borra (keep_recipe=True la
conserva). Sigue aunque uno falle y, al final, lanza el primer
error.
status() -> FleetStatus
async
¶
Estado de la flota: pregunta a los VMs que este proceso ya abrió
(GET /ping) y deja como unknown los demás.
wait_warm(timeout: float, poll: float) -> bool
async
¶
Espera a que las plazas calientes queden aparcadas; False si se
agota timeout (la flota funciona igual: las plazas son una
optimización de latencia).
invoke(prompt: str | None = None, session_id: str | None = None, model: str | None = None, reasoning: bool = False, *, input: Mapping[str, Any] | None = None) -> AgentResult
async
¶
Una invocación sin streaming: el AgentResult, con el id de sesión
enrutable si la flota puede tener varios VMs. Con input en lugar de
prompt, result.output trae la salida del grafo; se comprueba antes
de reservar un VM.
stream(prompt: str | None = None, session_id: str | None = None, model: str | None = None, reasoning: bool = False, *, input: Mapping[str, Any] | None = None) -> AsyncAgentFleetStream
async
¶
Como invoke(), con los eventos a medida que llegan. La petición se
hace aquí (un 429 se reintenta) y el VM queda ocupado hasta cerrar el
stream.
AgentFleetStream(stream: Any, *, sandbox_id: str, routable: bool, release: Callable[[str | None], None])
¶
El stream de una invocación de la flota: los eventos del VM con el id de sesión enrutable, y el VM liberado al cerrarlo.
AsyncAgentFleetStream(stream: Any, *, sandbox_id: str, routable: bool, release: Callable[[str | None], Awaitable[None]])
¶
El stream de una invocación de la flota asíncrona: los eventos del VM con el id de sesión enrutable, y el VM liberado al cerrarlo.
FleetStatus(name: str, members: tuple[FleetMemberStatus, ...], min_vms: int, max_vms: int, warm_vms: int, warm_ready: int, scaling_source: ScalingSource = 'default')
dataclass
¶
El estado de una flota: sus miembros, cuántos están sanos u ocupados y
los límites de ScalingOptions. Un miembro que este proceso aún no abrió
figura como unknown: preguntarle lo reanudaría. scaling_source dice
de dónde salen los límites: con default (sin proyecto ni receta) no
describen la flota real.
FleetMemberStatus(sandbox_id: str, state: MemberHealth, extra: bool, inflight: int)
dataclass
¶
AgentCore deploy¶
deploy_agent(target="agentcore") deploys the same project to Amazon Bedrock AgentCore Runtime and returns an AgentCoreFleet with the same invoke() and stream() as AgentFleet (Deploy to AgentCore). Without target, deploy_agent(), deploy_agent_async() and plan_deploy() do what they always did.
AgentCoreOptions(bedrock_models: tuple[str, ...] = (), readable_secrets: tuple[str, ...] = (), idle_session_timeout_seconds: int | None = None, max_session_lifetime_seconds: int | None = None, tags: Mapping[str, str] = dict(), external_model: bool = False)
dataclass
¶
Las opciones de un despliegue en AgentCore (deploy_agent(target=
"agentcore", agentcore=...)): bedrock_models (ids o ARNs de modelos o
perfiles de inferencia que el rol del runtime puede invocar, además del
modelo del proyecto), readable_secrets (nombres o ARNs de secretos de
Secrets Manager que el rol puede leer), idle_session_timeout_seconds y
max_session_lifetime_seconds (60-28800; None, 900 y 28800), tags
(etiquetas de la pila y del runtime, para organizaciones que las exigen)
y external_model (permite un modelo fuera de Bedrock: el rol no recibe
permisos de Bedrock que no pidas y la clave la obtiene tu código con
readable_secrets; nunca va en la configuración del runtime). Sólo valida los
tipos: los rangos se comprueban al planificar, antes de llamar a AWS.
Coste y activación¶
Activa: nada por sí mismo; el valor es puro. Lo que cuesta es
deploy_agent(target="agentcore").
Recursos y llamadas AWS: ninguno aquí; ver deploy_agent().
Coste aproximado: ninguno aquí; ver deploy_agent().
IAM: ninguna para este valor.
Cómo apagarla: los valores por defecto no dan al rol del runtime ningún
permiso de Bedrock extra ni de Secrets Manager, y sin
external_model=True un proveedor que no es Bedrock es
provider_unsupported.
Ejemplo:
AgentCoreOptions(bedrock_models=("amazon.nova-lite-v1:0",), tags={"team": "agents"})
AgentCoreDeployPlan(name: str, region: str, runtime_name: str, stack_name: str, repository_name: str, build_project_name: str, image_tag: str, bucket: str | None, bucket_source: str, network: str, bedrock_models: tuple[str, ...], readable_secrets: tuple[str, ...], environment: Mapping[str, str], lifecycle: AgentCoreLifecycle, tags: Mapping[str, str], steps: tuple[AgentCoreStep, ...], security: tuple[str, ...], warnings: tuple[str, ...], cost: tuple[str, ...], detection: object | None = None, target: str = 'agentcore', external_model: bool = False, secret_env_names: tuple[str, ...] = ())
dataclass
¶
Lo que deploy_agent(target="agentcore") haría, calculado sin llamar a
AWS: los nombres derivados, el bucket (o None si se descubre al
aplicar) y de dónde sale, los modelos y secretos del rol, el entorno y el
ciclo de vida del runtime, las etiquetas, los tres pasos, y las claves de
las líneas de seguridad y de los avisos (_messages.SECURITY_TEXTS y
WARNING_TEXTS), el coste de lista y si el modelo está fuera de Bedrock
(external_model). secret_env_names son las variables que el host
pondrá desde Secrets Manager (ADR-033 D4): sólo nombres, nunca
valores.
AgentCoreFleet(status: AgentCoreStatus, *, gateways: AgentCoreGateways, invoker: RuntimeInvoker)
¶
Bases: AgentCoreFleetView
Un agente desplegado en AgentCore Runtime. invoke() y stream()
tienen la firma y los resultados de AgentFleet: el session_id del
resultado es el que se usó (si pasas uno tuyo, el mismo id llega siempre a
la misma sesión), y pasarlo de nuevo continúa la conversación: cada sesión
corre en su propia microVM. status() lee el runtime, stop_session()
termina la microVM de una sesión y delete() borra el agente.
Coste y activación¶
Activa: crear la flota con deploy_agent(target="agentcore") o
AgentCoreFleet.connect() no llama a AWS más que para leer el
runtime; cada invoke() o stream() crea o reanuda una sesión de
AgentCore, que se factura por segundo de uso.
Recursos y llamadas AWS: InvokeAgentRuntime, StopRuntimeSession;
connect() y status() leen con ListAgentRuntimes y
GetAgentRuntime; delete() los de AgentCoreDeleter.
Coste aproximado: V1 de la plataforma, $0,0895 por vCPU-hora y $0,00945
por GB-hora de uso real, por segundo, sin cargo de CPU en espera de
E/S y con la memoria cobrada hasta que la sesión termina (15 min sin
uso por defecto); us-east-1, consultado 2026-10-19 en
https://aws.amazon.com/bedrock/agentcore/pricing/. El modelo lo cobra
Bedrock.
IAM: bedrock-agentcore:InvokeAgentRuntime, StopRuntimeSession,
ListAgentRuntimes y GetAgentRuntime.
Cómo apagarla: stop_session() termina una sesión; delete() borra el
agente; sin sesiones activas no hay cómputo.
Ejemplo:
fleet = AgentCoreFleet.connect("support-bot")
result = fleet.invoke("Resume el README.")
fleet.invoke("¿Y el de docs?", session_id=result.session_id)
connect(name: str, *, region: str | None = None, session: Any = None) -> Self
classmethod
¶
Reconstruye la flota del agente name desde su runtime, en
cualquier proceso. Si no hay ningún agente de Rayito con ese nombre en
la región, AgentCoreException con código runtime_not_found.
invoke(prompt: str | None = None, session_id: str | None = None, model: str | None = None, reasoning: bool = False, *, input: Mapping[str, Any] | None = None) -> AgentResult
¶
Una invocación sin streaming: el AgentResult, o AgentException si
el agente falló. result.session_id es el id que usó AgentCore.
stream(prompt: str | None = None, session_id: str | None = None, model: str | None = None, reasoning: bool = False, *, input: Mapping[str, Any] | None = None) -> AgentCoreFleetStream
¶
Como invoke(), con los eventos a medida que llegan:
with fleet.stream("hola") as events: for event in events.
status() -> AgentCoreStatus
¶
El runtime tal como está ahora (GetAgentRuntime).
stop_session(session_id: str) -> bool
¶
Termina la microVM de una sesión (StopRuntimeSession); False si
ya no existía. session_id se mapea igual que en invoke().
delete() -> AgentCoreDeleteResult
¶
Borra el agente: el runtime, la pila rayito-agentcore-<nombre>
(con el repositorio de ECR, el proyecto de CodeBuild y los roles) y el
grupo de logs del runtime. Sólo borra lo que Rayito creó con este
nombre.
AsyncAgentCoreFleet(status: AgentCoreStatus, *, gateways: AgentCoreGateways, invoker: RuntimeInvoker)
¶
Bases: AgentCoreFleetView
El espejo asíncrono de AgentCoreFleet: las mismas operaciones como
corrutinas (invoke, stream, status, stop_session, delete,
connect) y las mismas propiedades.
Coste y activación¶
Activa: crear la flota con deploy_agent_async(target="agentcore") o
AsyncAgentCoreFleet.connect() no llama a AWS más que para leer el
runtime; cada invoke() o stream() crea o reanuda una sesión.
Recursos y llamadas AWS: los de AgentCoreFleet.
Coste aproximado: el de AgentCoreFleet (V1: $0,0895 por vCPU-hora y
$0,00945 por GB-hora de uso real, us-east-1, consultado 2026-10-19 en
https://aws.amazon.com/bedrock/agentcore/pricing/).
IAM: los de AgentCoreFleet.
Cómo apagarla: await fleet.stop_session() termina una sesión; await
fleet.delete() borra el agente.
Ejemplo:
fleet = await AsyncAgentCoreFleet.connect("support-bot")
result = await fleet.invoke("Resume el README.")
connect(name: str, *, region: str | None = None, session: Any = None) -> Self
async
classmethod
¶
Reconstruye la flota del agente name desde su runtime.
invoke(prompt: str | None = None, session_id: str | None = None, model: str | None = None, reasoning: bool = False, *, input: Mapping[str, Any] | None = None) -> AgentResult
async
¶
Una invocación sin streaming: el AgentResult, o AgentException si
el agente falló. result.session_id es el id que usó AgentCore.
stream(prompt: str | None = None, session_id: str | None = None, model: str | None = None, reasoning: bool = False, *, input: Mapping[str, Any] | None = None) -> AsyncAgentCoreFleetStream
async
¶
Como invoke(), con los eventos a medida que llegan. La petición se
hace aquí, así que un error de AWS salta antes del primer evento.
status() -> AgentCoreStatus
async
¶
El runtime tal como está ahora (GetAgentRuntime).
stop_session(session_id: str) -> bool
async
¶
Termina la microVM de una sesión (StopRuntimeSession); False si
ya no existía.
delete() -> AgentCoreDeleteResult
async
¶
Borra el agente: el runtime, la pila y el grupo de logs del runtime.
AgentCoreFleetStream(stream: AgentDeploymentStream, session_id: str)
¶
El stream de una invocación: los eventos del agente con el id de
sesión que se usó (session_id); el último es Done o AgentFailed, y
result() lanza AgentException si el agente falló.
AsyncAgentCoreFleetStream(stream: AsyncAgentDeploymentStream, session_id: str)
¶
El stream asíncrono de una invocación: los eventos del agente con el id
de sesión que se usó (session_id); result() lanza AgentException si el
agente falló.
AgentCoreStatus(name: str, region: str, runtime_name: str, runtime_id: str, runtime_arn: str, runtime_version: str, status: str, image_uri: str, log_group: str)
dataclass
¶
El estado de un agente desplegado en AgentCore (GetAgentRuntime).
AgentCoreDeleteResult(name: str, region: str, runtime_deleted: bool, stack_deleted: bool, log_group_deleted: bool)
dataclass
¶
Lo que delete() borró: el runtime, la pila (con el repositorio, el
proyecto de CodeBuild y los roles) y el grupo de logs del runtime.
Runtime ports¶
They describe how a runtime is installed and served without changing the AgentRuntime port.
InstallableRuntime
¶
Bases: Protocol
Puerto opcional: lo que un runtime pone en la imagen. AgentTemplate
compone la imagen con los install_steps() de cada runtime.
ServableRuntime
¶
Bases: Protocol
Puerto opcional: cómo el host sirve un runtime (host_config).
HostConfig(driver: str, python: str, files: RuntimeFiles, envs: Mapping[str, str] = dict(), options: Mapping[str, object] = dict())
dataclass
¶
Lo que el host del agente necesita para servir un runtime: el
driver (lista cerrada HOST_DRIVERS), el intérprete python que
ejecuta el host, los ficheros a escribir antes de arrancar, las
variables de entorno y las opciones propias del driver.
GatewayWiring(urls: Mapping[str, str])
dataclass
¶
El modelo llega por las pasarelas del sandbox: urls por nombre de
pasarela (MicroVM). El agente sólo ve un marcador como clave.
DirectWiring()
dataclass
¶
Sin pasarela (contenedor exportado): el host lee la credencial de la fuente estándar del proveedor. La garantía de la pasarela no aplica.
ModelWiring: TypeAlias = GatewayWiring | DirectWiring
module-attribute
¶
InstallTarget(platform: InstallPlatform = 'microvm', python: str = DEFAULT_INSTALL_PYTHON, install_dir: str = DEFAULT_INSTALL_DIR)
dataclass
¶
Dónde instala un InstallableRuntime: descripción pura, sin I/O.
python es el intérprete con el que se crean los venvs y install_dir
la raíz de lo instalado.
is_installable(runtime: object) -> bool
¶
runtime implementa InstallableRuntime.
is_servable(runtime: object) -> bool
¶
runtime implementa ServableRuntime.
Listing¶
SandboxListPaginator(*, io: ListingIo, request: ListingRequest, resolve_template_arn: Callable[[str], str])
¶
Un listado reanudable (Sandbox.paginate), la forma del
SandboxPaginator de E2B.
next_token es opaco: guárdalo y pásalo a un Sandbox.paginate()
nuevo con los mismos filtros para seguir donde se quedó. No lo loguees:
lleva el ARN de la imagen y la huella de los filtros.
AsyncSandboxListPaginator(*, io: AsyncListingIo, request: ListingRequest, resolve_template_arn: Callable[[str], str])
¶
sandbox_sync.listing.SandboxListPaginator con next_items()
asíncrono. Construirlo no hace E/S.
next_token: str | None
property
¶
Antes de la primera llamada, el token recibido; después, el cursor
mientras has_next, si no None.