Enrutamiento entre agentes
Con la herramienta send_to_agent, un agente pasa trabajo a otro. Tú decides con exactitud quién puede llamar a quién, y en qué sentido.
Los agentes pueden comunicarse entre sí a través de la herramienta send_to_agent. Quién
tiene permiso para llamar a quién queda definido por una lista de rutas dirigida: el
campo can_message de cada agente enumera a quiénes puede escribirles ese agente en
concreto. Que exista una ruta de triage hacia billing no significa que también exista
la ruta inversa, de billing hacia triage.
Cada vez que un agente enruta un mensaje, el agente destino responde en una ejecución nueva, y esa respuesta llega de vuelta al que llamó como resultado de la herramienta. Un límite de saltos junto con una comprobación de ciclos evita que estas cadenas de llamadas entren en un bucle infinito.
Algo que send_to_agent nunca hace es cambiar con quién habla el usuario en realidad: es
una consulta puntual, así que el agente que llamó sigue siendo el que lleva la
conversación. Para entregar la conversación completa a otro agente existe una
herramienta distinta, switch_agent, que se explica más adelante.
Crear una ruta
# triage pasa trabajo a billing; billing puede escalar a refunds
pepe agent route triage billing
pepe agent route triage refunds
pepe agent route billing refunds
# revocar una ruta
pepe agent route triage billing --remove
# o definirla directamente al crear el agente
pepe agent add triage --model mock --can-message billing,refunds
Estas rutas quedan guardadas en ~/.pepe/config.json, dentro de la lista can_message de
cada agente:
"agents": {
"triage": { "can_message": ["billing", "refunds"] },
"billing": { "can_message": ["refunds"] },
"refunds": { "can_message": [] }
}
refunds tiene un can_message vacío: responde cuando otro agente lo llama, pero no
puede iniciar llamadas propias. Y como la lista es dirigida, dar de alta la ruta de
billing hacia refunds no otorga nada en el sentido contrario.
Para poder enrutar, el agente también necesita tener send_to_agent entre sus tools. La
lista de rutas decide a quién puede dirigirse; la herramienta es lo que le permite hacer
la llamada en sí.
--can-message se resuelve dentro del
propio proyecto del agente, y la CLI rechaza cualquier ruta entre dos agentes que
pertenezcan a proyectos distintos.Entregar toda la conversación, por ahora (switch_agent)
Si send_to_agent sirve para una consulta puntual, switch_agent cubre el otro caso: el
agente que está respondiendo en este momento le cede el resto de la conversación a
otro agente, activable con una petición en lenguaje natural (“ponme con billing”,
“quiero hablar directo con soporte”) sin necesitar ningún comando.
Ponme directamente con el agente de billing.
El agente llama a switch_agent con target: "billing". La respuesta a este turno
todavía sale del agente que venía respondiendo (“listo, te conecto ahora”); el cambio no
entra en vigor hasta el siguiente mensaje. El agente nuevo arranca con el contexto en
blanco: no hereda el historial de la conversación anterior.
Esto es temporal a propósito: dura solo hasta el próximo /new, que devuelve la
conversación al agente con el que realmente empezó. No es lo mismo que /agent NOMBRE (o pedirle al agente “vincula este canal a billing desde ahora, para siempre”) -
eso es un cambio permanente en la configuración del canal, cubierto en
Telegram y Webhooks, y es el tipo que el /new no
deshace. Usa switch_agent para “ponme con billing ahora”; usa el tipo permanente para
“este canal ahora es siempre de billing”.
switch_agent reutiliza la misma lista can_message de send_to_agent: si un agente
puede escribirle a otro, también puede cederle la conversación, sin necesidad de dar de
alta una ruta aparte. Igual que send_to_agent, switch_agent no pasa por la barrera
de permisos humana: la ruta ya es la autorización. Un canal que nunca debe cambiar de agente
usa agent_switch_locked, que lo rechaza de plano.
Cómo encaja el enrutamiento con la barrera de permisos
La propia lista de rutas funciona como autorización para la llamada a send_to_agent. El
operador ya decidió, en la configuración, que este agente puede escribirle a aquel otro,
así que esa llamada puntual no vuelve a pasar por la barrera de permisos: simplemente se
ejecuta.
Y es justo por eso que la lista es dirigida y parte cerrada, en lugar de ser simétrica y abierta. El permiso es estrecho y explícito, un sentido a la vez, lo que hace seguro dejarla pasar sin barrera. Una lista simétrica, en cambio, le regalaría en silencio al agente llamado una ruta de vuelta hacia quien lo llamó, algo que nadie pidió.
Las herramientas riesgosas del agente destino son otro tema, y siguen con su propia
barrera. Si billing ejecuta bash o write_file, esa llamada pasa por la barrera de
permisos exactamente igual que si hubieras hablado con billing directamente. El
enrutamiento le da a un agente acceso a otro, pero nunca le lava los permisos.
Cambiar rutas desde el chat
Si le das a un agente la herramienta manage_agent, podrá agregar o quitar rutas
conversando, guiado por la skill integrada manage-routing, para cualquier agente
sobre el que tenga autoridad can_manage (sin definir, el valor por defecto es
solo él mismo). Las acciones allow_route/deny_route reciben {target, value},
donde target es quien envía y value quien recibe.
Date permiso a ti mismo para escribirle al agente de billing.
El agente llama a manage_agent con action: "allow_route", target él
mismo, y value: "billing". Como esta acción modifica la configuración, sí
pasa por el aviso de permisos: tú autorizas la ruta nueva antes de que quede
escrita en disco. El enrutamiento sigue siendo dirigido, así que aprobar esta
ruta no habilita que billing te responda por su cuenta.