Saltar a contenido
06 de 06Coding agents y agent harnesses

Capítulo 6 — Tareas largas, memoria, subagentes, recuperación, merge y observabilidad

Biblioteca

Series y notas técnicas.

Estás en Coding agents y agent harnesses · Tareas largas, memoria y subagentes.

Serie

Coding agents y agent harnesses

6 contenidos

Ver vídeo, resumen y contenidos relacionados

Lectura estimada10 min

Un coding agent puede trabajar durante horas y seguir siendo frágil si toda su continuidad depende de una conversación viva.

Una tarea larga atraviesa cambios de contexto, procesos que reinician, streams que se desconectan, workers paralelos, branches que avanzan y verificaciones que envejecen. El problema ya no es sólo que el modelo recuerde qué estaba haciendo. El harness tiene que saber qué estado sigue siendo autoritativo, qué trabajo ya ocurrió, qué efectos externos son reales, qué evidencia sigue siendo válida y quién posee cada parte de la tarea.

La pregunta de este capítulo es concreta:

Text Only
¿qué debe sobrevivir para que una tarea pueda continuar,
recuperarse, delegarse e integrarse sin inventar continuidad?

La respuesta no es «más contexto». Es separar los estados que tienen ciclos de vida distintos.

Durabilidad · recovery · fan-in

La continuidad vive en el estado durable, no en un único contexto del modelo

El contexto puede compactarse o reiniciarse. La identidad de tarea, los workspaces, los efectos y la evidencia deben poder reconstruirse y volver a converger sobre un candidato integrado verificable.

Cómo sobrevive una tarea larga a cambios de contexto, subagentes y fallos Un contexto raíz en t0 se conecta a un ledger durable que conserva task ID, contrato, target, ownership y estado de efectos. Tras compaction o reset aparece un contexto raíz t1 que recupera el mismo ledger. El ledger delega dos work units a subagentes con workspaces y base SHA propios. Sus candidatos convergen con un target branch que avanza de A a B, creando un nuevo candidato integrado. Ese fan-in invalida evidencia dependiente de los candidatos anteriores y obliga a revalidar antes de merge. En paralelo, una desconexión se recupera abriendo un stream nuevo, recuperando estado guardado, reconciliando por IDs y aplicando eventos nuevos. Un rail inferior conserva observabilidad causal de root, subagentes, tools e integración. CONTEXTO TRANSITORIO CONTROL DURABLE OWNERSHIP + WORKSPACES PARALELOS FAN-IN · FRESHNESS · MERGE RECOVERY + OBSERVABILIDAD Contexto root t0mensajes + toolspuede desaparecer compact / resetcambia contexto Contexto root t1continúa la tarea Ledger durable de tarea task_id · contract_version · target_sha ownership · blockers · pending actions candidate/effect/evidence provenance sobrevive al contexto y al proceso persist / read Worker A · APIwork_unit_id=api · owner=Abase=A · workspace=WAcandidate=W1local tests/evidence belong to W1@A Worker B · migraciónwork_unit_id=db · owner=Bbase=A · workspace=WBcandidate=W2postcondition/evidence belong to W2@A Target Amain@A Target Bmain avanzó drift Candidato integrado I9integrate(B, W1, W2)nuevo SHA + diff combinado Evidence W1/W2dependiente → STALEI9 ≠ W1 ≠ W2 Reverify I9integration checksfresh evidence MERGEsólo tras I9 verified Disconnectstream/UI cae Nuevo streambuffer live events Retrieve saved statesession · items · actions Reconcile by IDitem_id · final state Continueapply new updates Causal traceroot · worker · tool · I9
estado / ejecucióninvalidación de evidenciarecovery / reconciliación

Regla operativa: perder contexto o transporte no debe borrar la identidad de la tarea. Tras fan-out o recovery, el sistema reconstruye estado por IDs durables; tras fan-in o cambio de target, deriva un nuevo candidate SHA e invalida toda evidencia que ya no pueda demostrarse fresh.

Una tarea larga es una máquina de estados durable, no una conversación infinita

En una interacción corta podemos fingir que conversación, plan, workspace y ejecución son una sola cosa. En una tarea de varias horas esa simplificación falla.

Conviene separar al menos cuatro planos:

Plano Ejemplos Qué puede invalidarlo
Contexto de inferencia mensajes recientes, resumen compactado, resultados seleccionados límite de contexto, reset, nueva sesión de modelo
Estado de control durable task_id, contrato, DAG, ownership, blockers, stop reason amendment autorizado, redistribución de trabajo
Estado de ejecución base SHA, candidate SHA, worktree, archivos, entorno, efectos externos nuevo commit, recreación del sandbox, cambio de target
Evidencia/provenance tests, reviews, postconditions, approvals, trace IDs cambio de candidate, contrato, entorno o verifier

Estos planos se relacionan, pero no son intercambiables.

Si el contexto se compacta, el candidate_sha no debería cambiar por ello. Si el proceso reinicia, un deploy que ya ocurrió no deja de haber ocurrido. Si el target branch avanza, una conversación perfectamente conservada no hace fresh una verificación antigua.

La unidad estable de una tarea larga debe ser una identidad durable, por ejemplo:

YAML
task_id: task-4812
contract_version: 4
target_ref: main
target_sha: a13f5c2
status: RUNNING
owners:
  api: worker-api
  migration: worker-db
candidate_sha: null

Es una estructura ilustrativa, no un estándar.

«Memoria» no es un único objeto

En agentes se usa memory para cosas diferentes:

Text Only
conversation history
summary / compaction state
facts or notes saved by the agent
plan and task graph
files created in the workspace
state of external systems
verification evidence

Agrupar todo bajo una palabra oculta decisiones importantes.

Una nota que dice «la migración ya está aplicada» no tiene la misma autoridad que una postcondition que consulta el esquema real. Un resumen de conversación puede recordar que existía un PR, pero no demuestra cuál es su head SHA actual.

Para producción es más útil preguntar:

Text Only
¿quién produjo este estado?
¿dónde vive?
¿qué identidad/version lo acompaña?
¿puede reconstruirse?
¿qué lo invalida?

Contexto, compaction, checkpoint y durable state tampoco son sinónimos

La compaction reduce o transforma el contexto que vuelve a entrar al modelo. Su objetivo es continuar razonando dentro de un presupuesto de tokens.

Un checkpoint es un punto de restauración. Puede incluir conversación, plan, archivos u otros objetos según el runtime.

El durable task state es el estado autoritativo que necesita el orquestador para reconstruir la tarea incluso si cambia el proceso o el contexto del modelo.

Es posible tener compaction sin un checkpoint completo. También puede existir un checkpoint de conversación que no incluya secretos, conexiones activas o estado en memoria de una tool.

GitHub documenta esta frontera explícitamente en Copilot SDK: con persistencia, una sesión puede reanudarse tras reinicios o migraciones de contenedor y se guardan historial, resultados de tools, planificación y artefactos; las API keys y el estado de tools sólo en memoria no se persisten.8

Por tanto:

Text Only
resume(session) ≠ restore(entire world exactly)

El harness debe saber qué parte restaura el runtime y qué parte debe rehidratar la aplicación.

Compaction y reset resuelven problemas distintos

No existe una política universal de contexto para tareas largas.

Anthropic describe una evolución concreta de su harness de desarrollo de larga duración: en una versión anterior usaba resets de contexto y handoff artifacts estructurados entre sesiones; posteriormente, con modelos más capaces, pudo mantener sesiones más largas y apoyarse en compaction automática. Su conclusión útil no es que «reset» o «compaction» gane siempre, sino que la cantidad de scaffolding necesaria depende del modelo y debe reevaluarse cuando éste cambia.7

OpenAI, por su parte, documenta en Agents API que el harness puede compactar automáticamente contexto anterior conforme una sesión se acerca al límite y mantener workflows que atraviesan múltiples ventanas de contexto.1

Esto es capacidad de un harness/servicio concreto, no una propiedad universal de cualquier modelo.

Una política razonable distingue:

Text Only
context continuity    → lo que el modelo necesita ahora
handoff artifact      → lo mínimo para que otro contexto entienda el trabajo
control state         → lo que el sistema debe conocer aunque ningún modelo lo recuerde
workspace state       → el código y los efectos realmente existentes

Un reinicio no debería convertir la memoria del modelo en source of truth

Supón que el proceso muere después de ejecutar:

Text Only
alembic upgrade head

pero antes de persistir «migration done» en la conversación.

Al arrancar de nuevo hay dos errores posibles:

Text Only
1. asumir que no ocurrió y repetir una mutación no idempotente
2. asumir que ocurrió porque el modelo lo recuerda, sin observar el sistema

El enfoque fail-closed es reconciliar estado durable con postconditions observables.

Para efectos externos, un ledger de acciones puede registrar:

YAML
action_id: db-migrate-019
intent: apply migration 20260911_03
request_fingerprint: 4db1...
started_at: 2026-09-11T09:14:20Z
observed_status: unknown
postcondition: schema_version == 20260911_03

Después del restart:

Text Only
si el outcome es durable y conocido → continuar
si es consultable → observar postcondition
si no puede saberse con seguridad → no repetir a ciegas; bloquear/reconciliar

Éste es un principio de diseño de 5sigmas para recuperación. No afirmamos que un provider concreto implemente automáticamente este ledger.

Recuperar un stream no es repetir el stream

Una desconexión de UI o transporte no implica que la tarea haya dejado de existir.

La documentación actual de OpenAI Agents API ofrece un ejemplo muy concreto: sus streams no reproducen eventos perdidos. Para recuperar la vista de la aplicación recomienda abrir un stream nuevo y bufferizar eventos, recuperar la sesión y sus items guardados, reconstruir estado local por item_id, aplicar las actualizaciones bufferizadas que sigan siendo relevantes y después continuar con eventos live.2

La forma es importante:

Text Only
reconnect
read durable history/state
reconcile by stable identity
apply only missing/new updates
continue live

No:

Text Only
reconnect → replay every command we think we missed

El mismo runtime documenta que, tras un restart o disconnect, la aplicación debe recuperar la sesión para descubrir required_actions pendientes.3

La lección general es separar event delivery de durable state. Un evento es una observación de una transición. No debería ser el único lugar donde existe el resultado de la transición.

Un estado idle o un stream cerrado no demuestra éxito

Los estados operativos necesitan semántica explícita.

Un esquema de control puede incluir:

Text Only
RUNNING
WAITING_FOR_AUTHORITY
WAITING_FOR_ENVIRONMENT
RECOVERING
DELEGATED
INTEGRATING
VERIFYING
ACCEPTED
REWORK_REQUIRED
HAND_BACK_TO_HUMAN
FAILED
CANCELLED

idle, «no hay más tokens» o «el socket se cerró» son observaciones del runtime, no success conditions del producto.

Agents API lo formula de forma explícita para su propio protocolo: una sesión idle o un stream cerrado no establecen success, y un turn completado tampoco garantiza que todas las tools hayan tenido éxito; hay que inspeccionar el output y los estados guardados.2

Subagentes sólo ayudan si ownership y dependencias son explícitos

Paralelizar no significa duplicar la misma tarea y esperar que el parent elija.

Un worker debería recibir un contrato suficiente para trabajar sin memoria implícita del parent:

YAML
work_unit_id: api-pagination
owner: worker-api
depends_on: [contract-v4]
base_sha: a13f5c2
scope:
  - src/api/**
  - tests/api/**
forbidden_scope:
  - migrations/**
expected_output:
  - candidate_sha
  - changed_paths
  - validation_results
  - blockers

GitHub Fleet mode documenta un patrón parecido: el parent descompone trabajo en todos con IDs durables y dependencias, cada subagente posee una unidad, los workers deben devolver cambios/validación/blockers y el parent debe verificar el resultado combinado. La propia documentación marca Fleet mode como experimental en varios SDKs y advierte que el paralelismo no elimina la reconciliación por parte del parent.9

Eso es capacidad y guidance de GitHub Copilot SDK, no una propiedad de todos los coding agents.

Cada subagente necesita su propia identidad de ejecución

Para poder depurar e integrar necesitamos distinguir:

Text Only
root_task_id
work_unit_id
agent_id / subagent_id
base_sha
workspace_id
candidate_sha
turn/run IDs
verifier evidence

OpenAI Agents API ofrece un ejemplo de esta atribución: cada subagent tiene su propio item history; los turns exponen subagent_id, y los eventos incluyen acciones de coordinación como crear, enviar input, esperar o interrumpir subagentes.4

También documenta un caveat útil: que una acción de create o wait haya terminado no significa que el subagente haya terminado su tarea.4

Por tanto, el estado correcto no es:

Text Only
wait_call = done → worker = successful

sino algo parecido a:

Text Only
worker lifecycle + output contract + verification → integration eligibility

No atribuyas al subagente capacidades que pertenecen al runtime

La frontera framework/provider vuelve a importar.

En la versión actual de Agents API, los subagentes heredan MCP tools configuradas, credenciales/allowed tools, web search y acceso a archivos/CLI del entorno, pero no soportan function tools.4

Eso es una restricción actual de ese producto en public beta. No demuestra que «los subagentes» en general no puedan ejecutar function tools.

Un artículo técnico debe conservar este nivel de atribución:

Text Only
modelo             → capacidad de inferencia
harness/runtime     → orchestration y lifecycle
provider/service    → persistencia/streaming/hosting concretos
application         → ownership, business state, policies y recovery contracts

Paralelismo seguro necesita una superficie de integración diseñada

Dos workers pueden producir commits que Git logra fusionar sin conflicto y aun así romper el sistema.

Ejemplo:

Text Only
worker A: cambia `User.id` de int a UUID en API
worker B: añade cache que sigue indexando por int

Los archivos no tienen por qué colisionar. La invariante sí.

Por eso el parent necesita una fase de integración:

Text Only
worker outputs
reconcile assumptions
integrate commits/artifacts
new integrated candidate SHA
run integration-level verification

Un merge limpio es evidencia sobre la mecánica de Git. No es una prueba de consistencia semántica.

El target branch puede moverse mientras los workers trabajan

Supón:

Text Only
t0: target main = A
worker-1 parte de A
worker-2 parte de A

t1: main avanza a B
workers producen W1 y W2 sobre A

Antes de mergear, el harness debe decidir explícitamente qué candidato quiere verificar:

Text Only
I = integrate(B, W1, W2)

Los tests ejecutados sobre W1@A no son automáticamente pruebas de I@B.

Esta es la misma regla de freshness del capítulo 5 aplicada a fan-out/fan-in:

Text Only
candidate identity changed → dependent evidence becomes stale

Puede reutilizarse evidencia sólo cuando la dependencia está explícitamente modelada y el cambio no puede afectarla. Si no se sabe, se revalida fail-closed.

Checkpoint de worker y checkpoint de integración son objetos diferentes

Un checkpoint de worker puede servir para continuar su rama:

Text Only
worker_id + base_sha + workspace + plan + local evidence

Pero el punto de integración necesita además:

Text Only
target_sha
worker candidate SHAs
merge/rebase operations
resolved conflicts
combined diff digest
integration candidate SHA
integration evidence

Esto evita un error común: marcar la tarea global como recuperable sólo porque cada worker puede reanudar su conversación.

Observabilidad útil reconstruye causalidad, no sólo logs

Para una tarea larga, «tenemos logs» no basta.

Una pregunta de producción típica es:

Text Only
¿por qué se aceptó este candidate SHA si el worker de migraciones había fallado 40 minutos antes?

Para responder necesitamos unir varias identidades:

Text Only
task_id
contract_version
root turn/run
subagent/work_unit
workspace + base_sha + candidate_sha
tool/action_id
status transition
retry/recovery relation
verifier/evidence IDs
integration candidate
stop_reason

OpenAI Agents API expone session/turn/item histories, atribución a subagentes y trazas de model responses, tool calls y delegated work.56

Pero sus propias docs establecen límites relevantes: usage es best-effort, puede ser null o cambiar, y no es la factura final; el public beta no expone configuración de tracing ni external trace exporters.56

Esto ilustra por qué observabilidad de provider y observabilidad de aplicación no son la misma capa.

Métricas de tarea larga: separa actividad de progreso

Contar tool calls o tokens puede medir trabajo sin medir avance.

Métricas operativas más informativas incluyen:

Métrica Pregunta que responde
tiempo en cada estado ¿dónde espera realmente la tarea?
work units ready/running/blocked ¿el DAG progresa o está atascado?
retries por causa ¿recuperamos o repetimos el mismo fallo?
stale evidence count ¿cuánto trabajo de verificación invalida la integración?
integration conflict rate ¿la descomposición produce ownership limpio?
recovery success ¿podemos continuar tras restart/disconnect sin intervención?
handback reason ¿qué autoridad/capacidad falta al sistema?
cost por outcome aceptado ¿cuánto cuesta cerrar trabajo válido, no sólo generar tokens?

Las métricas concretas dependen del producto. El principio es ligar actividad a estados y outcomes verificables.

Caso trabajado: tres workers y un target que avanza

Tarea:

Text Only
Añadir `external_id` a cuentas.
Exponerlo en REST.
Migrar datos existentes.
Actualizar documentación y tests.

Contrato inicial:

YAML
task_id: account-external-id
contract_version: 2
target_sha: A

El parent crea:

Text Only
W1 API        base=A   owns src/api/** + tests/api/**
W2 migration  base=A   owns migrations/** + tests/db/**
W3 docs       base=A   owns docs/**

Cada worker devuelve:

YAML
work_unit_id: migration
base_sha: A
candidate_sha: M7
changed_paths:
  - migrations/20260911_external_id.py
verification:
  migration_up: pass
  migration_down: pass
blockers: []

Mientras trabajan, main avanza de A a B.

El parent no debería decir:

Text Only
W1 pass + W2 pass + W3 pass → merge

Debe construir el candidato integrado:

Text Only
I9 = integrate(B, W1, W2, W3)

Después:

Text Only
1. recalcular changed paths e invariantes cruzadas
2. invalidar evidencia dependiente de A/W1/W2/W3 cuando corresponda
3. ejecutar integration tests y contract checks sobre I9
4. revisar conflictos semánticos y cambios de target
5. aceptar sólo si la evidencia final pertenece a I9

Si el proceso del parent cae después de crear I9, el restore necesita poder reconstruir que I9 existe y qué evidencias están fresh. Releer conversaciones de los tres workers no sustituye ese ledger.

Recovery correcto tiene que ser repetible

Un buen test de arquitectura es preguntar:

Text Only
si mato el orchestrator ahora mismo,
¿puede otro proceso decidir exactamente qué hacer después sin adivinar?

Para acercarse a «sí» hacen falta al menos:

Text Only
identidades estables
durable control state
workspace/candidate identities
acción y effect provenance
worker ownership + dependencies
pending authority/actions
evidence freshness
explicit stop reasons

Y una regla de reconciliación:

Text Only
persisted state + observed external state → next safe transition

No:

Text Only
last model message → guess next action

Trade-off: durabilidad y paralelismo cuestan complejidad

Persistir cada transición, mantener un DAG, aislar workspaces, conservar provenance y revalidar integración añade trabajo al harness.

No todas las tareas lo necesitan.

Para una corrección de cinco minutos en un repo local, un solo agente, un worktree y una suite de tests pueden ser suficientes. Para una migración de varias horas con efectos remotos y tres workers, depender sólo del transcript es una apuesta innecesaria.

La pregunta práctica es:

Text Only
¿cuánto estado puede perderse sin que el sistema tenga que adivinar?

Cuanto mayor sea la duración, el paralelismo, la autoridad de las tools y el coste de repetir efectos, más valor tiene hacer durable el estado de control y evidencia.

La arquitectura debe poder simplificarse cuando cambia el modelo

El harness no debe acumular mecanismos sólo porque fueron útiles una vez.

El trabajo de Anthropic sobre long-running coding muestra precisamente que cambios de modelo pueden cambiar qué scaffolding aporta valor: estrategias necesarias para una generación anterior pueden convertirse en overhead con una nueva.7

De forma similar, un managed harness puede asumir parte de la persistencia, compaction, subagent lifecycle o tracing que una implementación thin/vanilla tendría que construir.

Pero transferir una responsabilidad al runtime no elimina la necesidad de conocer su boundary. La aplicación sigue necesitando sus propios contratos de negocio, ownership, candidate identity y success criteria.

Implicación de producción: continuidad significa poder reconstruir verdad

Una tarea larga no es fiable porque el modelo pueda seguir hablando después de diez horas.

Es fiable cuando el sistema puede responder, después de un reset, un restart, una desconexión o un fan-in:

Text Only
qué tarea estamos ejecutando
qué contrato está vigente
qué trabajo posee cada actor
qué efectos ya ocurrieron
qué candidate es el actual
qué evidencia pertenece a ese candidate
qué está bloqueado
qué transición es segura ahora
por qué aceptaríamos o devolveríamos la tarea

Ese es el salto de un coding assistant persistente a un harness operable.

La continuidad útil no consiste en conservar cada token. Consiste en conservar suficiente estado autoritativo para reconstruir la verdad del trabajo y volver a verificar todo lo que dejó de ser válido.

Referencias primarias


  1. OpenAI, Introducing the Agents API, 10 de septiembre de 2026. Se usa para las capacidades first-party anunciadas de long sessions, compaction, subagents y separación entre harness y entorno. No se usan customer testimonials ni benchmarks de marketing como evidencia general. 

  2. OpenAI API Docs, Agents API — Events and items. Se usan las semánticas actuales de event/item identity, estado de turns/items y el algoritmo documentado para reconstruir estado tras desconexión; los streams no replayean eventos perdidos. 

  3. OpenAI API Docs, Agents API — Manage sessions. Se usa la semántica de requires_action, recuperación de acciones pendientes tras restart/disconnect y lifecycle de sesión. 

  4. OpenAI API Docs, Agents API — Multi-agent. Se usan únicamente capacidades actuales del producto: subagent histories, subagent_id, coordination items, herencia de MCP/tools permitidas y la limitación actual de function tools. 

  5. OpenAI API Docs, Agents API — Observability and usage. Se usan session/turn/item observability y los caveats de usage best-effort. 

  6. OpenAI API Docs, Agents API — Tracing. Se usan las definiciones actuales de trace/span y la limitación del public beta respecto a configuración y external exporters. 

  7. Anthropic, Harness design for long-running application development, 24 de marzo de 2026. Se usa como evidencia first-party de handoff artifacts, context reset vs compaction, planner/generator/evaluator y de que el scaffolding necesario cambia con la capacidad del modelo. No se generalizan sus costes ni tiempos a otros setups. 

  8. GitHub Docs, Copilot SDK — Session resume and persistence. Se usa para distinguir qué estado persiste y qué debe reinyectarse al reanudar una sesión. 

  9. GitHub Docs, Copilot SDK — Fleet mode. Se usa su patrón actual de ownership/dependencies, worker result contract y parent verification, conservando explícitamente su estado experimental. 

Continúa aprendiendo
Serie completadaElige la siguiente rutaTodas las series