Lección 07 · Memoria

Estado en disco que sobrevive a la compresión

«State that survives compression — because it's outside the conversation.»

⏱ ~10 min · 📝 3 widgets interactivos · 🧑‍💻 Basado en shareAI-lab · s07_task_system.py

¿En qué se diferencia TodoWrite del Task system?

El TodoManager de s03 también gestiona tareas — pero las guarda en memoria. Cuando auto_compact de s06 se dispara y reemplaza messages[] por un summary, el estado del TodoManager desaparece con él (porque es in-memory).

El Task de s07 es diferente: cada tarea es un archivo .tasks/task_42.json. Tanto si el contexto se comprime, como si el proceso se reinicia, o incluso si se cambia de agent — mientras el archivo de disco exista, la tarea existe.

# .tasks/task_12.json
{
  "id": 12,
  "subject": "Refactor auth middleware",
  "description": "Extract JWT logic to shared module",
  "status": "pending",
  "blockedBy": [8, 11],   # debe completar #8 y #11 primero
  "owner": ""
}
Regla de selección: para tareas temporales (se hacen y se olvidan) usa todo; para tareas persistentes (que deben sobrevivir entre sesiones o tienen dependencias) usa task.

blockedBy · la mecánica del grafo de dependencias

blockedBy es una lista de IDs de tarea — todas deben estar en estado completed antes de que la tarea actual sea «ejecutable».

Hay un detalle elegante en s07: al completar una tarea, esta se elimina automáticamente del array blockedBy de todas las demás tareas.

def _clear_dependency(self, completed_id: int):
    # Scan every task, remove completed_id from their blockedBy
    for f in self.dir.glob("task_*.json"):
        task = json.loads(f.read_text())
        if completed_id in task.get("blockedBy", []):
            task["blockedBy"].remove(completed_id)
            self._save(task)

Así el agent no necesita mantener una tabla aparte de «qué tareas quedaron desbloqueadas» — basta con recorrer .tasks/ y buscar las que tengan status=="pending" and not blockedBy para saber qué se puede hacer ahora.

Interacción con el grafo de dependencias

El siguiente widget te da un grafo de 5 tareas. Pulsa «complete» en cualquiera y observa cómo se actualiza blockedBy y qué tareas pasan a ser «ejecutables» (resaltadas en verde).

¿Sobreviven a la compresión?

s06 demostró que auto_compact reemplaza messages[] por un summary. Las tasks no se ven afectadas, porque están en disco. Pruébalo: el agent crea 5 tasks, se comprime el contexto y luego, al hacer un scan de .tasks/, las recupera todas.

Interactivo

Widget 1 · Dependency Graph · pulsa complete y ve cómo se actualizan las dependencias

Topología de 5 tasks. Pulsa Start o Complete en cualquier task disponible y observa cómo cambia el array blockedBy y la lista «próximas ejecutables».

Lista de tasks (directorio .tasks/)
Ejecutables ahora (status=pending, blockedBy=[])
Grafo de dependencias
Interactivo

Widget 2 · Compression Survival · las tasks sobreviven a auto_compact

El agent crea 3 tasks, se dispara auto_compact (messages se vacía) y luego recupera todo escaneando el disco.

Directorio .tasks/
messages[]
Interactivo

Widget 3 · Dependency Chain · dado el estado actual, ¿qué tasks se pueden iniciar?

5 tasks con dependencias en distintos estados. Responde qué tareas están disponibles para iniciar ahora (puede haber más de una respuesta correcta).

Correctas 0 / 4