Phase 13 - Lesson 13

Tareas Asíncronas (SEP-1686) — Chame Ahora, Busque Después para Trabajo de Larga Duración

This lesson includes a graded coding exercise that runs in your browser, unlocked with lifetime access.

El trabajo real del agente toma de minutos a horas: ejecuciones de CI, síntesis de investigación profunda, exportaciones por lotes. Las llamadas a herramientas síncronas caen conexiones, expiran o bloquean la interfaz de usuario. SEP-1686, fusionado el 25/11/2025, agrega una primitiva de Tareas: cualquier solicitud puede aumentarse para convertirse en una tarea, y el resultado puede obtenerse más tarde o transmitirse a través de notificaciones de estado. Nota de riesgo de desviación: las Tareas son experimentales hasta el primer semestre de 2026; la superficie del SDK aún se está diseñando en torno a la especificación.

Tipo: Build Idiomas: Python (stdlib, máquina de estados de tareas asíncronas) Prerrequisitos: Fase 13 · 07 (servidor MCP), Fase 13 · 09 (transportes) Tiempo: ~75 minutos

Objetivos de Aprendizaje

  • Identificar cuándo promover una herramienta de síncrona a aumentada por tarea (>30 segundos de trabajo en el servidor).
  • Recorrer el ciclo de vida de la tarea: workinginput_requiredcompleted / failed / cancelled.
  • Persistir el estado de la tarea para que las fallas no pierdan el trabajo en progreso.
  • Consultar tasks/status y obtener tasks/result correctamente.

El Problema

Una herramienta generate_report ejecuta una canalización de extracción de varios minutos. Opciones bajo el modelo síncrono:

  1. Mantener la conexión abierta durante tres minutos. Los transportes remotos la caen; los clientes expiran; las interfaces de usuario se congelan.
  2. Retornar inmediatamente con un marcador de posición; requerir que el cliente consulte un punto de conexión personalizado. Rompe la uniformidad de MCP.
  3. Ejecutar y olvidar; sin resultado.

Ninguno es bueno. SEP-1686 agrega un cuarto: aumento de tarea. Cualquier solicitud (típicamente tools/call) puede etiquetarse como una tarea. El servidor devuelve un ID de tarea de inmediato. El cliente consulta tasks/status y obtiene tasks/result cuando termina. El estado en el servidor sobrevive a los reinicios.

El Concepto

Aumento de tarea

Una solicitud se convierte en una tarea al establecer params._meta.task.required: true (o optional: true, el servidor decide). El servidor responde de inmediato con:

{
  "jsonrpc": "2.0", "id": 1,
  "result": {
    "_meta": {
      "task": {
        "id": "tsk_9f7b...",
        "state": "working",
        "ttl": 900000
      }
    }
  }
}

ttl es la promesa del servidor de retener el estado; después de ttl, el resultado de la tarea se descarta.

Opción por herramienta

Las anotaciones de herramientas pueden declarar soporte para tareas:

  • taskSupport: "forbidden" — esta herramienta siempre se ejecuta sincrónicamente. Seguro para herramientas rápidas.
  • taskSupport: "optional" — el cliente puede solicitar aumento de tarea.
  • taskSupport: "required" — el cliente DEBE usar aumento de tarea.

Una herramienta generate_report sería required. Una herramienta notes_search sería forbidden.

Estados

working  -> input_required -> working  (loop via elicitation)
working  -> completed
working  -> failed
working  -> cancelled

La máquina de estados es de tipo append-only: una vez que está en completed, failed o cancelled, la tarea es terminal.

Métodos

  • tasks/status {taskId} — devuelve el estado actual y una indicación de progreso.
  • tasks/result {taskId} — bloquea o devuelve 404 si aún no se ha completado.
  • tasks/cancel {taskId} — idempotente; los estados terminales lo ignoran.
  • tasks/list — opcional; enumera las tareas activas y completadas recientemente.

Transmisión de cambios de estado

Cuando el servidor lo soporta, el cliente puede suscribirse a notificaciones de estado:

server -> notifications/tasks/updated {taskId, state, progress?}

Los clientes que transmiten en lugar de realizar consultas obtienen una mejor experiencia de usuario (UX). Las consultas siempre se admiten como la superficie mínima.

Estado durable

La especificación exige que los servidores que declaran soporte de tareas persistan el estado. Una falla no debe perder resultados completados dentro del ttl. Los almacenamientos varían desde SQLite a Redis hasta el sistema de archivos. El entorno de la Lección 13 utiliza el sistema de archivos.

Semántica de cancelación

tasks/cancel es idempotente. Si la tarea está a mitad de la ejecución, el servidor intenta detenerla (verificar la cancelación cooperativa del ejecutor). Si ya es terminal, la solicitud es una operación sin efecto (no-op).

Recuperación de fallas

Cuando el proceso del servidor se reinicia:

  1. Cargar todos los estados de tareas persistidos.
  2. Marcar cualquier tarea working cuyo proceso haya muerto como failed con el error CRASH_RECOVERY.
  3. Preservar completed / failed / cancelled para su ttl.

Tareas asíncronas más muestreo

Una tarea puede, por sí misma, llamar a sampling/createMessage. Así es como funcionan las tareas de investigación de larga duración: el hilo de la tarea del servidor muestrea el modelo del cliente según sea necesario, mientras la interfaz de usuario del cliente muestra la tarea como working con actualizaciones periódicas de progreso.

Por que esto es experimental

SEP-1686 se lanzó el 25/11/2025, pero la hoja de ruta más amplia señala tres problemas abiertos: primitivas de suscripción duraderas, subtareas (relaciones de tareas padre-hijo) y estandarización de TTL de resultados. Se espera que la especificación evoluya a lo largo de 2026. El código de producción debe tratar las Tareas como estables solo para el caso común y protegerse contra futuros cambios del SDK para subtareas.

Úsalo

code/main.py implementa un almacenamiento de tareas durable (respaldado por sistema de archivos) y una herramienta generate_report que se ejecuta en un hilo en segundo plano. Los clientes llaman a la herramienta, obtienen un ID de tarea de inmediato, consultan tasks/status mientras el ejecutor actualiza el progreso y obtienen tasks/result cuando termina. El cancelación funciona; la recuperación de fallas se simula matando el hilo del ejecutor y recargando el estado.

Qué observar:

  • Estado de la tarea JSON persistido en /tmp/lesson-13-tasks/<id>.json.
  • El hilo del ejecutor actualiza el campo progress; la consulta muestra que avanza.
  • La cancelación desde el lado del cliente establece un evento; el ejecutor lo comprueba y sale temprano.
  • La recarga del estado tras una "falla" marca la tarea en curso como failed con CRASH_RECOVERY.

Entrégalo

Esta lección produce outputs/skill-task-store-designer.md. Dada una herramienta de larga duración (investigación, compilación, exportación), la habilidad diseña el almacenamiento de tareas (forma del estado, ttl, durabilidad), elige la bandera taskSupport correcta y esboza las notificaciones de progreso.

Ejercicios

  1. Ejecuta code/main.py. Inicia una tarea generate_report, consulta el status y luego obtén el resultado.
  2. Agrega una llamada tasks/cancel a mitad de la ejecución. Verifica que el ejecutor la respete y el estado pase a ser cancelled.
  3. Simula la recuperación de fallas: mata el hilo del ejecutor, reinicia el cargador y observa el modo de falla CRASH_RECOVERY.
  4. Extiende el almacenamiento a SQLite. Los beneficios de durabilidad son los mismos; las opciones de consulta se amplían (listar todas las tareas de la sesión X).
  5. Lee la publicación de la hoja de ruta de MCP para 2026. Identifica el único problema abierto relacionado con las Tareas que tiene más probabilidades de afectar el diseño de la API del SDK en el próximo año.

Términos Clave

Término Lo que la gente dice Lo que realmente significa
Task "Llamada a herramienta de larga duración" Solicitud aumentada con _meta.task para ejecución asíncrona
SEP-1686 "Especificación de tareas" Propuesta de Evolución de Especificación (SEP) que agregó Tareas el 25/11/2025
_meta.task "Sobre de la tarea" Metadatos por solicitud que contienen id, state, ttl
taskSupport "Bandera de la herramienta" forbidden / optional / required por herramienta
tasks/status "Método de consulta" Obtiene el estado actual y una indicación de progreso opcional
tasks/result "Obtener resultado" Devuelve la carga útil completada o 404 si aún no se ha realizado
tasks/cancel "Detenerlo" Solicitud de cancelación idempotente
ttl "Presupuesto de retención" Milisegundos que el servidor promete mantener el estado de la tarea
notifications/tasks/updated "Envio de estado" Evento de cambio de estado iniciado por el servidor
Almacenamiento durable "Estado a prueba de fallas" Capa de persistencia en sistema de archivos / SQLite / Redis

Lectura Adicional

0 lifetime access. Curriculum based on AI Engineering from Scratch by Rohit Ghumare (MIT, used under attribution).