Tabla de Contenidos
- El Problema con los Agentes Efímeros
- Cómo Funciona Session Storage
- Implementación: Coding Agent con Session Storage en AgentCore Runtime
- Lo Que el Filesystem Soporta (y lo que no)
- Cuándo Usar Session Storage (y Cuándo No)
- Lo Que Aprendí Probándolo
- La Imagen Completa: Las Tres Capas de Estado de un Agente
- Recursos Oficiales 📚
Tu agente de código nunca más empezará desde cero: Session Storage en AgentCore Runtime
Imagina este escenario: tu coding agent pasó los últimos 40 minutos scaffoldeando un proyecto Node.js. Instaló dependencias, escribió los modelos, configuró el ORM, dejó las pruebas unitarias a medio terminar. Tienes que cerrar la sesión. Al día siguiente retomas el trabajo — y el agente empieza desde cero. Sin archivos. Sin node_modules. Sin ningún rastro de lo que construyó.
Eso no es un bug de tu agente. Es el comportamiento por diseño de cualquier runtime de agentes sin persistencia. Cada sesión arranca desde un filesystem limpio.
Y hay una distinción importante que vale la pena hacer antes de entrar al código:
Memoria episódica (que cubrimos en el artículo anterior) guarda lo que aprendió el agente: patrones, reflexiones, experiencias pasadas. Session Storage guarda lo que construyó: archivos, dependencias, artefactos, estado operacional del proyecto.
Son dos formas de persistencia complementarias, no intercambiables. Un agente de producción serio necesita las dos.
Hoy nos enfocamos en la segunda.
El Problema con los Agentes Efímeros
El runtime de AgentCore, como cualquier sistema de cómputo serverless, es efímero por diseño. Cuando una sesión termina o se detiene, el computo asociado se destruye. La próxima vez que invoques la misma sesión, AWS provisiona un nuevo entorno limpio.
Para agentes conversacionales simples, esto no es un problema. Para coding agents, agentes de análisis de datos de larga duración, o cualquier agente que trabaje con el filesystem, es un bloqueante serio:
- El agente instala paquetes → sesión se detiene → debe reinstalar todo
- El agente genera artefactos intermedios → sesión se reinicia → archivos perdidos
- El agente hace checkpoints de un proceso largo → reinicio → sin checkpoints
Las soluciones tradicionales son dolorosas: sincronizar con S3 manualmente, usar EFS con configuración VPC, o escribir lógica de checkpoint propia. Todas funcionan, pero agregan complejidad operacional que el equipo tiene que mantener.
AgentCore Runtime Session Storage es la respuesta gestionada de AWS a este problema.
Cómo Funciona Session Storage
Session Storage es una capacidad gestionada del AgentCore Runtime. Tu agente lee y escribe en un directorio local normal — digamos /mnt/workspace — y el runtime replica ese estado de forma transparente hacia almacenamiento durable.
El ciclo de vida es el siguiente:
- Primera invocación de una sesión — Se provisiona nuevo compute. El directorio en el mount path aparece vacío.
- El agente escribe archivos — Operaciones normales de filesystem (
mkdir,write,npm install,git init). Los datos se replican asíncronamente al storage durable. - La sesión se detiene — El compute se destruye. Los datos pendientes de replicar se flushean durante el shutdown graceful.
- Siguiente invocación con el mismo
sessionId— Nuevo compute, pero el filesystem se restaura exactamente donde quedó.
Lo que más me llamó la atención al probarlo: no hay API especial para esto. Tu agente simplemente usa el filesystem como siempre. El runtime maneja todo lo demás.
⚠️ Importante: Cuando llames explícitamente a
StopRuntimeSession, espera a que la operación complete antes de retomar la sesión. Esto garantiza que todos los datos se flusheen al storage durable antes del siguiente inicio.
Aislamiento por Sesión
Cada sesión tiene su propio storage aislado. Una sesión no puede leer ni escribir en el storage de otra sesión del mismo agente, ni de agentes distintos. Esto es importante para casos multi-tenant o cuando múltiples usuarios tienen sesiones paralelas con el mismo agente.
Ciclo de Vida del Storage
Los datos persisten mientras la sesión esté activa. Hay dos condiciones que reinician el filesystem a estado limpio:
- La sesión no es invocada por 14 días consecutivos.
- La versión del agent runtime es actualizada. Si haces un deploy nuevo, las sesiones existentes arrancarán con filesystem vacío.
Este segundo punto es un gotcha real para producción: si tienes sesiones de larga duración activas y haces un deploy, pierden su estado de filesystem. Diseña tu agente para manejar este caso.
Implementación: Coding Agent con Session Storage en AgentCore Runtime
Vamos a construir un coding agent que demuestre la persistencia en acción: crea un proyecto, se detiene, retoma y continúa donde quedó — tanto en archivos como en conversación.
Prerequisitos
Antes de empezar, verifica que tienes:
- AWS CLI configurado con permisos sobre
bedrock-agentcore-controlyecr - Docker con Buildx — ejecuta
docker buildx versionpara confirmar - Repositorio ECR creado en tu cuenta para la imagen del agente
- Región: Session Storage está disponible en múltiples regiones (us-west-2, us-east-1, eu-central-1, ap-northeast-1 y otras) — consulta la lista actualizada en la documentación oficial antes de desplegar
pip install strands-agents strands-agents-tools bedrock-agentcore boto3
Rol IAM para el Agent Runtime
El runtime necesita un rol que AgentCore pueda asumir. La trust policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "bedrock-agentcore.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
Y la permissions policy con los permisos mínimos necesarios:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:GetAuthorizationToken"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:us-west-2:TU_CUENTA:*"
}
]
}
Estructura del Proyecto
Tres archivos en el mismo directorio:
coding-agent/
├── Dockerfile
├── coding_agent.py
└── requirements.txt
El Contenedor
AgentCore Runtime ejecuta contenedores ARM64 exclusivamente. Si desarrollas en una máquina x86/amd64, necesitas cross-compilation con Docker Buildx:
# Crear un builder para ARM64
docker buildx create --use
# Build + push directo a ECR
docker buildx build \
--platform linux/arm64 \
-t TU_CUENTA.dkr.ecr.us-west-2.amazonaws.com/coding-agent:latest \
--push .
⚠️ Gotcha: Si usas
docker buildnormal sin buildx, la imagen resultante será amd64 aunque estés en una máquina ARM. AgentCore la rechazará conArchitecture incompatible. En mi experiencia, cuando la cross-compilation desde x86 no producía una imagen ARM válida, usar el driverdocker-containerexplícito (--driver docker-container) lo resolvió — pero la documentación oficial solo requieredocker buildxsin especificar driver. Si tienes problemas con la arquitectura, ese es el primer ajuste a probar.
El Dockerfile necesita Python para el agente y Node.js porque el agente crea proyectos Node:
FROM python:3.12-slim
WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends \
git curl && rm -rf /var/lib/apt/lists/*
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y nodejs \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY coding_agent.py .
RUN mkdir -p /mnt/workspace
EXPOSE 8080
CMD ["python", "coding_agent.py"]
Y el requirements.txt:
strands-agents
strands-agents-tools
bedrock-agentcore
boto3
El Agente
from strands import Agent
from strands.session import FileSessionManager
from strands.models import BedrockModel
from strands_tools import file_read, file_write, shell
from bedrock_agentcore.runtime import BedrockAgentCoreApp
# Habilita herramientas sin confirmación interactiva
os.environ["BYPASS_TOOL_CONSENT"] = "true"
app = BedrockAgentCoreApp()
# El workspace persiste entre sesiones gracias a Session Storage
WORKSPACE = "/mnt/workspace"
model = BedrockModel(
model_id="us.anthropic.claude-sonnet-4-20250514-v1:0"
)
tools = [file_read, file_write, shell]
@app.entrypoint
def handle_request(payload):
session_id = payload.get("session_id", "default")
# El historial de conversación también persiste en el workspace
# — mismo directorio, sin costo adicional
session_manager = FileSessionManager(
session_id=session_id,
storage_dir=f"{WORKSPACE}/.sessions"
)
agent = Agent(
model=model,
tools=tools,
session_manager=session_manager,
system_prompt=(
"Eres un coding assistant. "
"Los archivos del proyecto están en /mnt/workspace. "
"Cuando retomes una sesión, primero revisa qué hay en el workspace "
"antes de asumir que debes empezar desde cero."
)
)
response = agent(payload.get("prompt"))
return {
"response": response.message["content"][0]["text"]
}
if __name__ == "__main__":
app.run()
Observa el punto de diseño en el system_prompt: le indicamos al agente que revise el workspace antes de actuar. Sin esto, el agente podría no “notar” que hay archivos existentes y proponer empezar de nuevo. La persistencia de filesystem es transparente para el runtime, pero el agente necesita saber que debe buscarla.
El FileSessionManager guarda el historial de conversación en /mnt/workspace/.sessions/ — el mismo directorio que persiste. Esto significa que el agente también recuerda qué prometió hacer en la sesión anterior, no solo los archivos que creó.
Configurar el Agent Runtime con Session Storage
Al crear el agent runtime, agrega filesystemConfigurations con un sessionStorage:
# deploy.py
import boto3
import argparse
REGION = "us-west-2"
ACCOUNT_ID = "TU_CUENTA"
RUNTIME_NAME = "coding_agent"
ROLE_ARN = f"arn:aws:iam::{ACCOUNT_ID}:role/AgentExecutionRole"
CONTAINER_URI = f"{ACCOUNT_ID}.dkr.ecr.{REGION}.amazonaws.com/coding-agent:latest"
client = boto3.client("bedrock-agentcore-control", region_name=REGION)
def create_runtime():
response = client.create_agent_runtime(
agentRuntimeName=RUNTIME_NAME,
roleArn=ROLE_ARN,
agentRuntimeArtifact={
"containerConfiguration": {
"containerUri": CONTAINER_URI
}
},
networkConfiguration={
"networkMode": "PUBLIC" # Requerido si tu agente necesita acceso a internet (Bedrock, npm, pip)
},
filesystemConfigurations=[
{
"sessionStorage": {
"mountPath": "/mnt/workspace"
}
}
]
)
arn = response["agentRuntimeArn"]
# AWS agrega un sufijo aleatorio al nombre: coding_agent-XXXXXXXXXX
# Consulta el ARN completo con:
# aws bedrock-agentcore-control list-agent-runtimes
print(f"✅ Agent Runtime creado: {arn}")
return arn
def update_runtime(runtime_id: str):
"""Agrega session storage a un runtime existente."""
client.update_agent_runtime(
agentRuntimeId=runtime_id,
filesystemConfigurations=[
{
"sessionStorage": {
"mountPath": "/mnt/workspace"
}
}
]
)
print(f"✅ Session Storage agregado al runtime {runtime_id}")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--create", action="store_true")
parser.add_argument("--update", type=str, metavar="RUNTIME_ID")
args = parser.parse_args()
if args.create:
create_runtime()
elif args.update:
update_runtime(args.update)
else:
print("Uso: python deploy.py --create | --update RUNTIME_ID")
Dos detalles que vale la pena conocer:
networkConfigurationconnetworkMode: "PUBLIC"es necesario si tu agente necesita acceso a internet — para llamar a Bedrock, descargar paquetes npm o pip, etc. No es un parámetro obligatorio de la API si tu agente opera en VPC sin necesidad de salida a internet.- AWS agrega un sufijo aleatorio al nombre que diste — el ARN real del runtime tiene formato
coding_agent-XXXXXXXXXX. Consúltalo conaws bedrock-agentcore-control list-agent-runtimesdespués del deploy.
Si ya tienes un runtime existente, update_agent_runtime acepta el mismo parámetro filesystemConfigurations para agregarlo sin recrear el runtime.
El Ciclo Stop/Resume en Acción
# client.py
import boto3
from botocore.config import Config
import json
import os
import time
REGION = "us-west-2"
# AWS agrega sufijo automático al nombre dado en create_agent_runtime.
# Consulta el ARN exacto con: aws bedrock-agentcore-control list-agent-runtimes
AGENT_ARN = os.environ.get(
"AGENT_ARN",
"arn:aws:bedrock-agentcore:us-west-2:TU_CUENTA:runtime/coding_agent-XXXXXXXXXX"
)
# Mismo sessionId en todas las invocaciones = mismo filesystem persistente.
# Mínimo 33 caracteres — AgentCore lo valida en el cliente.
SESSION_ID = "proyecto-api-rest-001-session-demo-01"
# read_timeout=300 es necesario: npm install y operaciones largas
# superan fácilmente el default de 60 segundos de boto3.
client = boto3.client(
"bedrock-agentcore",
region_name=REGION,
config=Config(read_timeout=300)
)
def invoke(prompt: str, conv_id: str = "conv-001") -> str:
response = client.invoke_agent_runtime(
agentRuntimeArn=AGENT_ARN,
runtimeSessionId=SESSION_ID,
payload=json.dumps({
"prompt": prompt,
"session_id": conv_id
}).encode()
)
result = json.loads(b"".join(response["response"]))
return result["response"]
def stop_session():
print(f"⏹ Deteniendo sesión {SESSION_ID}...")
client.stop_runtime_session(
agentRuntimeArn=AGENT_ARN,
runtimeSessionId=SESSION_ID
)
# La documentación oficial recomienda explícitamente esperar que StopRuntimeSession
# complete antes de retomar la sesión — garantiza que el flush al storage durable
# termine. En producción, implementa un poll del estado de sesión en lugar de un sleep fijo.
print("⏳ Esperando flush al storage durable...")
time.sleep(15)
print("✅ Sesión detenida. Filesystem persistido.")
# --- Primera invocación ---
print(invoke(
"Crea un proyecto Node.js en /mnt/workspace/api. "
"Inicializa con npm (nombre: 'rest-api', versión '1.0.0'), "
"instala express y dotenv, y crea index.js con un "
"endpoint GET /health que retorne {status: 'ok', timestamp: Date.now()}."
))
# --- Detener la sesión ---
stop_session()
# --- Segunda invocación con el mismo sessionId ---
# El agente retoma con filesystem y conversación intactos
print(invoke(
"Agrega un endpoint POST /echo que retorne el body recibido "
"como JSON. Revisa primero qué existe en el workspace."
))
En mis pruebas, la segunda invocación retomó exactamente donde quedó: node_modules intacto, package.json con las dependencias ya definidas, y el historial de conversación que le permitió al agente entender qué había creado antes.
Lo Que el Filesystem Soporta (y lo que no)
Session Storage implementa un filesystem Linux estándar en el mount path. Operaciones comunes que funcionan sin modificación:
ls, cat, mkdir, touch, mv, cp, rm
git init / git add / git commit
npm install / pip install / cargo build
chmod, chown, stat, readdir
Las operaciones POSIX estándar funcionan. Hay cuatro excepciones documentadas que vale la pena conocer antes de diseñar tu agente:
Hard links — No soportados. Usa symlinks si los necesitas. La mayoría de herramientas de desarrollo no los usan directamente.
Device files, FIFOs, UNIX sockets — mknod no está soportado. Afecta casos muy específicos (servidores Unix socket, etc.).
Extended attributes (xattr) — Herramientas que dependen de metadatos xattr no funcionarán.
fallocate — Preallocación de archivos sparse no soportada. Herramientas que la usan explícitamente fallarán; las que simplemente escriben archivos, no.
File locking entre sesiones — Los advisory locks funcionan dentro de una sesión activa, pero no persisten entre stop/resume. git no se ve afectado porque no depende de locks persistentes.
Un detalle de comportamiento: los permisos (chmod) se almacenan correctamente y stat los reporta bien, pero el enforcement no aplica dentro de la sesión porque el agente corre como único usuario en el microVM. No afecta el comportamiento de herramientas estándar, pero es algo a considerar si tu agente crea archivos con permisos específicos esperando que se respeten.
Cuándo Usar Session Storage (y Cuándo No)
La pregunta que más me hicieron cuando lo compartí con el equipo: “¿esto reemplaza a EFS?”
No exactamente. Aquí está la comparativa honesta:
| Criterio | Session Storage | EFS propio | S3 manual | Sin persistencia |
|---|---|---|---|---|
| Configuración | 1 parámetro en el deploy | VPC + mount target + sg | Código de sync | Ninguna |
| Aislamiento | Por sesión, automático | Manual (tu lógica) | Manual (tu lógica) | N/A |
| Límite de duración | 14 días sin invocación | Mientras exista el EFS | Mientras exista el bucket | 0 (ephemeral) |
| Efecto de deploy | Resetea filesystem | No afecta | Depende de tu lógica | N/A |
| Costo | Preview — pricing por confirmar | EFS + datos transferidos | S3 por operación | Ninguno |
| Multi-sesión compartido | No (aislado por sesión) | Sí, posible | Sí, posible | N/A |
Usa Session Storage cuando:
- Tu agente trabaja con proyectos de código que se extienden en múltiples sesiones
- Necesitas persistencia operacional sin overhead de configuración
- Cada sesión es independiente y no necesita compartir storage con otras
- Quieres que el estado del filesystem sobreviva reinicios sin escribir código de checkpoint
Considera alternativas cuando:
- Múltiples sesiones del mismo agente necesitan acceso al mismo filesystem compartido (EFS)
- Tu caso requiere más de 14 días de inactividad sin reset (EFS o S3)
- Haces deploys frecuentes de tu agent runtime y el reset de filesystem es problemático
- Tienes requisitos específicos de compliance sobre dónde se almacenan los datos
Lo Que Aprendí Probándolo
Algunas observaciones del mundo real que no están en la documentación oficial:
El system_prompt importa tanto como la configuración. Session Storage es transparente para el runtime, pero el LLM necesita contexto para “notar” que hay trabajo previo. Sin indicarle que revise el workspace antes de actuar, el agente puede proponer empezar de nuevo aunque los archivos estén ahí.
FileSessionManager de Strands es el complemento natural. Guardar el historial de conversación en el mismo /mnt/workspace es elegante: un solo mecanismo de persistencia para estado operacional y contexto conversacional.
Espera explícita después del stop no es opcional. La documentación oficial es explícita: “always wait for [StopRuntimeSession] to complete before resuming the session”. En mis pruebas, retomar sin esperar resultó en errores 500 del runtime. Un time.sleep(15) mínimo funcionó de forma consistente, pero en producción implementa un poll del estado de sesión en lugar de un sleep fijo.
El read_timeout de boto3 te va a morder. El default es 60 segundos. Un coding agent que ejecuta npm install o pip install supera ese límite fácilmente y recibes un ReadTimeoutError que parece un error del runtime pero es del cliente. Configura Config(read_timeout=300) en el cliente de bedrock-agentcore.
ARM64 es el único formato soportado. docker build normal en una máquina x86 produce una imagen amd64 que AgentCore rechaza con Architecture incompatible. Usa docker buildx --platform linux/arm64. Si tienes problemas con la arquitectura resultante al hacer cross-compilation desde x86, agregar el driver explícito --driver docker-container al crear el builder fue lo que resolvió el problema en mi caso.
runtimeSessionId requiere mínimo 33 caracteres. El código de ejemplo oficial lo documenta con un comentario inline: # Must be 33+ chars. Un ID corto fallará al invocar el agente.
AWS agrega un sufijo aleatorio al nombre del runtime. El ARN real tiene formato coding_agent-XXXXXXXXXX. Consúltalo con aws bedrock-agentcore-control list-agent-runtimes después del deploy.
El efecto del deploy en filesystems activos. Actualizar la versión del agent runtime resetea el filesystem de todas las sesiones activas. Si tienes sesiones de trabajo largo en vuelo, un deploy las interrumpe. Considera esto en tu estrategia de release.
La Imagen Completa: Las Tres Capas de Estado de un Agente
Con este artículo, la serie ha cubierto las tres capas de estado que un agente de producción en AgentCore puede manejar:
- AgentCore Policy — Lo que el agente puede hacer. Límites determinísticos.
- AgentCore Memory Episódica — Lo que el agente aprendió. Experiencias y patrones.
- AgentCore Session Storage — Lo que el agente construyó. Estado operacional del filesystem.
Ninguna reemplaza a la otra. Un coding agent de producción serio puede beneficiarse de las tres al mismo tiempo: Policy para limitar qué comandos puede ejecutar, Memory Episódica para aprender de patrones de código o errores pasados, y Session Storage para mantener el workspace entre sesiones.
La combinación hace que “agente que trabaja en proyectos reales” sea un caso de uso viable, no solo una demo de re:Invent.
¿Estás construyendo coding agents o agentes de análisis de larga duración en AWS? ¿Cuál ha sido tu mayor reto con la persistencia de estado? Me interesa saber qué están enfrentando — los comentarios están abiertos.
¡Hasta el próximo artículo! 🚀
¿Te fue útil este artículo? Compártelo con tu equipo. Probablemente también tienen un agente que “olvida” todo cada vez que se reinicia.
Inicia la conversación