Bucle del agente
Explica cómo Copilot CLI procesa un mensaje del usuario de extremo a extremo (desde el envío del prompt hastasession.idle).
Arquitectura
El SDK es la capa de transporte. Envía los prompts al Copilot CLI mediante JSON-RPC y retransmite los eventos a tu aplicación. El CLI es quien ejecuta el bucle de uso de herramientas al estilo agente, orquestando una o más llamadas a la API del LLM hasta completar la tarea.Bucle de uso de herramientas
Cuando llamas asession.send({ prompt }), el CLI entra en el siguiente bucle:
En cada llamada, el modelo consulta todo el historial de la conversación (system prompt, mensaje del usuario y todas las llamadas a herramientas y sus resultados hasta ese momento).
Importante: una iteración de este bucle equivale exactamente a una llamada a la API del LLM y aparece en el log de eventos como un par assistant.turn_start / assistant.turn_end. No hay llamadas ocultas.
Qué es un turn
Un turn es una llamada a la API del LLM y su resultado.- El CLI envía el historial de la conversación al LLM
- El LLM responde (posiblemente incluyendo solicitudes de herramientas)
- Si hay solicitudes de herramientas, el CLI las ejecuta
- Se emite
assistant.turn_end
| Turn | Comportamiento del modelo | ¿toolRequests? |
|---|---|---|
| 1 | Busca en la base de código con grep y glob | ✅ Sí |
| 2 | Lee ficheros concretos según los resultados de la búsqueda | ✅ Sí |
| 3 | Lee más para obtener contexto adicional | ✅ Sí |
| 4 | Genera la respuesta final en texto | ❌ No → termina el bucle |
Flujo de eventos con varios turns
Quién inicia cada turn
| Actor | Responsabilidad |
|---|---|
| Tu app | Envía el prompt inicial con session.send() |
| Copilot CLI | Ejecuta el bucle de uso de herramientas y devuelve los resultados de la ejecución al LLM como entrada del siguiente turn |
| LLM | Decide si continuar solicitando herramientas o devolver la respuesta final y terminar |
| SDK | Solo retransmite eventos. No controla el bucle |
Diferencias entre session.idle y session.task_complete
Ambas son señales de finalización, pero garantizan cosas muy distintas.
session.idle
- Se emite siempre al terminar el bucle de uso de herramientas
- Es efímera: no se persiste en disco ni se reproduce al reanudar la sesión
- Significado: «el agente ha dejado de procesar y puede aceptar el siguiente mensaje»
- Úsala como señal fiable de «terminado»
sendAndWait() espera este evento.
session.task_complete
- Se emite opcionalmente (solo cuando el modelo lo señala explícitamente)
- Es persistente (se guarda en el log de eventos de la sesión)
- Significado: «el propio agente considera que la tarea global se ha cumplido»
- Puede incluir un
summaryopcional
Modo autopilot: el CLI empuja al modelo a llamar a task_complete
En el modo autopilot (headless / autónomo), el CLI hace un seguimiento de si el modelo ha llamado a task_complete. Si el bucle de uso de herramientas termina sin task_complete, el CLI inyecta el siguiente mensaje sintético de usuario para instar al modelo:
“You have not yet marked the task as complete using the task_complete tool. If you were planning, stop planning and start implementing. You aren’t done until you have fully completed the task.”Con esto, el bucle de uso de herramientas se reanuda de hecho. El modelo recibe ese aviso como un nuevo mensaje de usuario y continúa el trabajo. El aviso incluye también «no llames a
task_complete demasiado pronto»:
- No lo llames si quedan dudas sin resolver. Decide y sigue trabajando.
- No lo llames solo por haber encontrado un error. Intenta resolverlo.
- No lo llames si quedan tareas pendientes. Termínalas primero.
- El modelo llama a
task_completecon un summary → el CLI emitesession.task_complete→ terminado - El modelo se detiene sin llamarlo → el CLI le insiste → el modelo continúa o llama a
task_complete
Por qué puede no aparecer task_complete
En el modo interactive (chat convencional), el CLI no empuja hacia task_complete. El modelo puede omitirlo. Principales razones:
- Q&A conversacional: responde a la pregunta y termina, sin una «tarea» discreta que completar
- Decisión del modelo: devuelve el texto final sin llamar a
task_complete - Sesión interrumpida: la sesión termina antes de que el modelo llegue a un punto de finalización
session.idle porque no es una señal semántica (el modelo lo considera completo) sino mecánica (el bucle terminó).
¿Cuál deberías usar?
| Caso de uso | Señal |
|---|---|
| «Esperar a que el agente termine de procesar» | session.idle ✅ |
| «Saber que una tarea de programación ha terminado» | session.task_complete (best-effort) |
| «Gestionar timeouts / errores» | session.idle + session.error ✅ |
Contar el número de llamadas al LLM
El número de paresassistant.turn_start / assistant.turn_end del log de eventos coincide con el total de llamadas a la API del LLM. No hay llamadas ocultas de planificación, evaluación o verificación de finalización.
Ejemplo para comprobar el número de turns de una sesión:
Documentación relacionada
- Eventos de streaming — referencia a nivel de campo de cada tipo de evento
- Reanudar sesiones — guardar y reanudar sesiones
- Hooks de sesión — interceptar eventos del bucle (permisos, herramientas)