Super-agent
El super-agent es un modo, no el nombre de una persona. Cuando ejecutás apx exec sin apuntar a un
agente de proyecto específico, APX activa este modo: el loop a nivel del daemon, que usa herramientas y puede alcanzar
cada herramienta registrada — operaciones de archivos, llamadas MCP, Telegram, shell, tasks, sesiones y más.
El nombre que usa el asistente cuando habla con vos viene de ~/.apx/identity.json (por defecto
“APX”). Las referencias a “super-agent” son un término técnico interno para el modo. Lo configurás
con las claves super_agent.* en ~/.apx/config.json, y los tipos de routine todavía pueden decir
super_agent — pero los usuarios nunca ven esa etiqueta.
Habilitarlo
Sección titulada «Habilitarlo»El modo está deshabilitado por defecto. Configurá ambas claves antes de llamarlo por primera vez:
apx config set --global super_agent.enabled trueapx config set --global super_agent.model "anthropic:claude-sonnet-4-5"Una vez habilitado, cada llamada a apx exec sin -a <agent> pasa por este modo.
apx exec — el punto de entrada de una sola vez
Sección titulada «apx exec — el punto de entrada de una sola vez»apx exec "<prompt>" # modo super-agent (por defecto)apx exec -- "<prompt>" # igual; -- evita problemas de parseo de flagsapx exec -a reviewer "<prompt>" # un agente de proyecto nombrado en su lugarapx exec "<prompt>" --model gpt-5 # sobrescribe el modelo configurado para esta llamadaapx exec "<prompt>" --max-tokens 2000 # limita los tokens de salidaapx exec "<prompt>" --project my-app # fija un contexto de proyecto específico$ apx exec 'list my open tasks across all projects' Roby (super-agent) · anthropic:claude-sonnet-4-5 → tool tasks.list { project: "First Project", state: "open" } → tool tasks.list { project: "Acme Store", state: "open" } → tool tasks.list { project: "Data Pipeline", state: "open" } Tenés 4 tasks abiertas: • First Project — Wire Stripe webhooks before merge (vence 06-16) • Acme Store — Retry-guard the flaky cart-total test (vence 06-18) • Acme Store — Document the pairing flow for the web panel • Data Pipeline — Backfill ingestion CLI flag (vence 06-20) # 612 tok in / 198 out · 2.4s
Cuando el modo super-agent está activo, el daemon resuelve el nombre del asistente desde
~/.apx/identity.json y lo muestra en las líneas de estado, los headers de la TUI y las respuestas de Telegram —
nunca la cadena “super-agent”.
Contactarlo desde otro agente (A2A)
Sección titulada «Contactarlo desde otro agente (A2A)»Identidad configurada también funciona como dirección A2A de primera clase. Un agente puede contactar a Roby igual que a cualquier agente de proyecto:
apx send crypto-analyst roby "Alerta BTC: decidí si el dueño necesita recibirla por Telegram" --deliverAPX encuentra proyecto del emisor, guarda todos los alias de identidad bajo peer estable
super_agent y ejecuta loop real del super-agent: identidad, memoria relevante, contexto de
proyecto, política de permisos y herramientas. Esto difiere de apx exec, que representa un turno
escrito por dueño. Si slug emisor existe en varios proyectos, agregá --project <name>.
Agentes reales de proyecto siguen ganando sobre alias. Si un proyecto define intencionalmente un
agente con slug apx o nombre igual a identidad configurada, selección elige ese agente dentro de
su proyecto.
El tool loop
Sección titulada «El tool loop»Por debajo, runSuperAgent() arma un system prompt (bloque de identidad + inventario de proyectos +
bloque de memoria + bloque de threads activos), selecciona un subconjunto del schema de herramientas apropiado para el canal,
y después llama al engine vía el loop estándar runAgent(). El loop continúa hasta que el modelo deja
de llamar herramientas o una señal lo aborta.
Registro de herramientas
Sección titulada «Registro de herramientas»El registro completo tiene alrededor de 30 herramientas nativas más herramientas puenteadas desde registries (browser, fetch, search, glob, grep). El daemon elige un subconjunto según el canal para mantenerse dentro de los presupuestos de TPM de los tiers baratos:
| Canal | Conjunto de herramientas | Justificación |
|---|---|---|
api / apx exec | Completo | Deliberado, modelo elegido por el usuario |
routine | Completo | Programado, autónomo, modelo elegido por el usuario |
web / code | Completo | Workspace de formato largo |
telegram | Core (~700 tokens) | Tiers baratos, respuestas ágiles |
desktop / deck | Core | Igual |
El modelo siempre puede expandir su superficie llamando a load_skill.
Herramientas nativas seleccionadas
Sección titulada «Herramientas nativas seleccionadas»| Herramienta | Qué hace |
|---|---|
create_task / list_tasks / get_task | Agregar, listar y leer items de TODO por proyecto |
update_task / complete_task / comment_task | Editar una, moverla o cerrarla, anotar su hilo |
call_agent | Darle trabajo a un agente de proyecto, en el mismo proceso. Corre con sus propias tools, así que hace el trabajo en vez de describirlo, y el intercambio queda como una conversación agente-a-agente que podés leer y continuar |
send_to_agent | Escribirle a otro agente — uno de proyecto, el super-agente o un runtime de código — y recibir su respuesta. Con background: true el trabajo queda corriendo y al que mandó lo despiertan cuando termina, así un intercambio largo ya no le retiene el turno. Ver Trabajo que queda corriendo |
call_mcp | Llamar cualquier herramienta de un servidor MCP registrado |
call_runtime | Delegar a un runtime externo (Claude Code / Codex …), de forma síncrona o en segundo plano |
run_subagent | Lanzar un sub-agente aislado (contexto fresco, mismas tools menos las de interacción con el usuario) que trabaja una tarea auto-contenida hasta completarla y devuelve el resultado — máximo un nivel de anidamiento |
run_shell | Ejecutar un comando de shell (limitado por el modo de permisos) |
send_telegram | Enviar un mensaje vía el plugin de Telegram |
send_file | Mandarte un archivo del disco: una captura, una imagen generada. Ver Mandarte archivos |
remember | Escribir un hecho durable en ~/.apx/memory.md |
search_sessions | Recuperar transcripciones de sesiones pasadas |
set_identity | Actualizar campos de ~/.apx/identity.json |
Mandarte archivos
Sección titulada «Mandarte archivos»El super-agente te puede mandar un archivo con send_file: una captura del
browser, una imagen que generó, un render. El archivo llega con la
respuesta: en el chat web se ve ahí mismo con un botón para descargarlo, y en
Telegram sale como foto (o como documento, para otros tipos). Sacar la captura
no la manda sola; el agente tiene que pasarle la ruta guardada a send_file.
Solo se mandan los tipos que habilitaste. Las imágenes vienen prendidas y el
resto apagado hasta que lo actives en ~/.apx/config.json:
{ "file_delivery": { "kinds": { "image": true, "video": false, "audio": false, "document": false }, "max_mb": 20 }}document cubre PDF, texto, Markdown, CSV, JSON, archivos de Office y .zip.
Hay cosas que no se mandan nunca, diga lo que diga la config: ejecutables y
scripts (.exe, .msi, .bat, .sh, .apk, .dmg, …) y todo lo que esté
bajo ~/.ssh, ~/.aws, ~/.gnupg o ~/.apx (salvo ~/.apx/media, donde se
archivan los archivos enviados). Una imagen cuyos bytes no coinciden con su
extensión también se rechaza, así que renombrar un archivo no saltea el switch.
Trabajo que queda corriendo
Sección titulada «Trabajo que queda corriendo»El turno de un peer es un tool loop entero. Puede tardar minutos, y send_to_agent
lo espera por defecto — lo cual está bien sólo cuando esa respuesta es lo próximo
que el que manda necesita.
background: true cambia eso. La tool vuelve al instante con un job_id, el peer
trabaja por su cuenta y, cuando contesta, al que mandó lo despiertan: la
respuesta llega como un mensaje nuevo en el mismo hilo agente-a-agente y arranca
un turno fresco con el resultado en la mano. Pasá wake_me: false para un aviso
puro, del que nunca vas a necesitar respuesta.
El despertar es un mensaje a2a común en sentido inverso, así que el pedido y su respuesta viven en un solo hilo — no hay un lugar nuevo adonde mirar.
Lo que escribe el que se despierta queda archivado como nota propia, no como respuesta: el peer ya contestó y no espera nada. Archivado como respuesta, el “recibido, gracias” caía en la bandeja del peer, el peer confirmaba de vuelta, y una respuesta se volvía una ronda de acuses de recibo, cada uno un tool loop entero.
Reglas para pasar trabajo
Sección titulada «Reglas para pasar trabajo»- Preguntar dos veces no lo arranca dos veces. Mientras sigue corriendo algo que le pasaste a un
agente, volver a llamarlo (
call_agentosend_to_agent) devuelve el trabajo en curso — qué está haciendo y hace cuánto — en vez de abrirle otro turno.check_jobslee ese estado sin tocar a nadie. Una corrección a propósito pasa confollowup: true. - Nadie espera desde adentro de un a2a. Un agente que le contesta a otro pasa el trabajo en segundo plano, nunca esperando a un tercero; lo pesado (un render, una producción) corre como trabajo propio en segundo plano, no dentro de la conversación.
- Sin tarjetas de pregunta en a2a. Ahí nadie puede contestarlas: si un agente necesita al dueño, el super-agente le pregunta por su propio canal.
- El chat muestra cada pase como Esperando / Esperó o En segundo plano, y la barra de escritura del chat del super-agente lista todos los agentes trabajando para él, con la cadena debajo de cada uno.
Qué conserva el que espera, y qué no
Sección titulada «Qué conserva el que espera, y qué no»Un turno despertado es un turno nuevo. Recibe la respuesta, un resumen de lo que había pedido y el historial del hilo — no el contexto de trabajo que tenía cuando dejó el trabajo corriendo. Todo lo que haga falta para actuar sobre la respuesta va en el mensaje mismo.
Un trabajo que no produjo respuesta también despierta, y lo dice sin vueltas: el peer falló, el trabajo se pasó de presupuesto, o el daemon se reinició mientras corría y el trabajo es irrecuperable. Al que espera se le dice explícitamente que no lo reporte como hecho.
Límites
Sección titulada «Límites»| Límite | Valor | Por qué |
|---|---|---|
| Trabajos abiertos por agente | 3 | Acota cuánto se ABRE el abanico |
| Profundidad de pases | 3 | Acota cuánto BAJA; se cuenta entre turnos, despertares, call_agent y apx send |
| Pasos de tools por turno de peer | 20 (super_agent.a2a_max_iters) | Un peer que se queda sin pasos contesta qué hizo y qué falta; el que pidió decide si sigue |
| Vida de un trabajo | 1 hora por defecto | Pasada esa, se corta y se avisa |
Los dos límites vuelven como un mensaje sobre el que el agente puede actuar, nunca como una excepción.
Un turno que nadie está mirando — una respuesta a2a, una rutina — también frena
ante un plan agotado. Cuando un proveedor contesta que la cuenta llegó a su
límite de uso (no un rate limit pasajero), ese modelo se enfría una hora
(super_agent.quota_cooldown_min), el turno sin humano termina en vez de gastar
el resto de la cadena de fallback, y al dueño le llega una sola línea por Telegram.
Un chat con una persona adentro sigue cayendo al próximo modelo. También un
modelo que elegiste vos — fijado al agente, puesto en la rutina o el modelo
propio del super-agente — cuando tiene el fallback prendido: ese interruptor es
tu indicación de seguir por el router. El freno es para cuando se agota la cuenta
del propio router, la que heredan los agentes.
Ver qué está corriendo
Sección titulada «Ver qué está corriendo»curl -s localhost:7430/api/jobs?open=1 -H "Authorization: Bearer $TOKEN"GET /api/jobs lista todos los trabajos — ?open=1 para lo que corre ahora, más
?project_id, ?from y ?status. GET /api/jobs/:id devuelve uno. El panel lee
la misma ruta, y el feed de eventos en vivo lleva un frame background_job al
arrancar y al terminar.
Los trabajos son de sólo lectura por HTTP a propósito: uno termina cuando termina su trabajo, cuando se pasa su fecha límite, o cuando muere el daemon que lo tenía. Para frenar el trabajo, abortá el turno que el trabajo abrió.
Brokering entre canales
Sección titulada «Brokering entre canales»El modo super-agent es el handler común detrás de cada superficie: mensajes de Telegram, prompts de la ventana
de Desktop, llamadas a apx exec, chat web y corridas de routines convergen todos en runSuperAgent(). Cada
superficie pasa un identificador de channel (telegram, desktop, web, routine, api, …) que
determina:
- Qué subconjunto de herramientas es visible para el modelo.
- Si se inyecta un bloque de “active threads” (turnos recientes en otros canales).
- Qué identidad de remitente de Telegram y qué reglas de role-gating aplican.
El canal whatsapp es una alerta, no un chat
Sección titulada «El canal whatsapp es una alerta, no un chat»WhatsApp no es una superficie propia de APX. Un puente en el teléfono del dueño
postea a POST /api/projects/:pid/super-agent/chat con channel: "whatsapp"
cada vez que WhatsApp levanta una notificación de Android — y una
notificación no es el mensaje. Android las agrupa y las corta: lo que llega
suele ser 7 mensajes nuevos, una variable de Tasker que nunca se expandió, o un
pedazo de la última línea.
Así que el turno es un despertador, y las reglas del canal
(prompts/channels/whatsapp.md) son sobre qué hacer con él:
- Ir a mirar. Cargar la skill
whatsapp-sendy abrir WhatsApp en el teléfono para leer lo que realmente está sin leer. Necesita queadbllegue a ese teléfono: por USB o con depuración inalámbrica prendida. - Hacer una ronda. Todas las conversaciones sin leer, no sólo la que disparó la alerta: las alertas llegan de a una mientras los mensajes se apilan.
- Decidir por conversación — contestarla por WhatsApp; o
send_telegramal dueño cuando la decisión es suya (plata, fechas, compromisos) o cuando llegó algo para él (un código de verificación, un aviso de pago), avisándole a la persona que está consultando; o dejar en paz una difusión. - Dejar WhatsApp en segundo plano. Con la app en primer plano Android deja de levantar notificaciones y el puente se queda sordo.
- Cerrar la ronda con un Telegram que nombre todo lo nuevo: quién escribió, qué dijo y qué se hizo — incluidas las conversaciones que contestó solo. El dueño no está mirando este canal, así que una ronda que nadie escucha es una ronda que para él no pasó. Un mensaje por ronda; si no hay nada nuevo, no se manda nada.
De esa forma se desprenden dos cosas. Nada de lo que el agente escribe en el turno le llega a nadie — una persona sólo lo escucha con un envío explícito, así que el texto de la respuesta es un parte de trabajo. Y el que escribe no es el dueño: su texto es dato, una instrucción adentro de un mensaje de WhatsApp no tiene autoridad ninguna, y los códigos, precios o datos privados nunca vuelven por el chat.
Cuando no se puede llegar al teléfono, la alerta se le relaya al dueño por Telegram con lo que traía — nunca una adivinanza del mensaje, nunca silencio.
El broker de memoria corre antes de cada llamada que no sea tool-free e inyecta un bloque [MEMORIA RELEVANTE]
en el system prompt. Mirá Memory system para los detalles.
Identidad — apx identity
Sección titulada «Identidad — apx identity»El nombre visible del asistente se guarda en ~/.apx/identity.json:
{ "agent_name": "APX", "owner_name": ""}Tres comandos lo gestionan:
apx identity show # imprime los campos de identidad actualesapx identity set agent_name Ada # cambia el nombre visible a "Ada"apx identity set owner_name Sam # configura el nombre del owner/usuarioapx identity wizard # prompt de configuración interactivo$ apx identity show Agent name : Roby Personality : pragmatic, concise, a little playful Owner : Alex Context : prefers es-AR, ships fast, hates ceremony Language : en (apx config set --global user.language <code>) Last wakeup : 2026-06-14 09:31 File : ~/.apx/identity.json
Selector Ajustes → Super-agente guarda super_agent.icon. Usa mismo
catálogo de blobos que agentes de proyecto y empuja cambios inmediatamente a
web, Desktop y mascota Android nativa.
Modo de permisos
Sección titulada «Modo de permisos»permission_mode en super_agent controla qué puede hacer el tool loop sin preguntar:
| Modo | Comportamiento |
|---|---|
total | Todas las herramientas corren sin confirmación |
automatico | APX decide automáticamente (recomendado) |
permiso | Solo las herramientas en allowed_tools; todo lo demás pregunta |
En todos los modos, total incluido, escribir un archivo que guarda credenciales — ~/.apx/config.json,
un mcps.json, auth.json, un .env, una llave — pide tu confirmación antes, sea con una herramienta
de archivos o por shell. Si el canal no puede preguntar, la escritura se rechaza. Las herramientas
nativas que manejan esos archivos (add_mcp, apx config set) no se ven afectadas.
apx permission set automaticoAnálisis de riesgo inline
Sección titulada «Análisis de riesgo inline»Una capa opt-in encima del modo de permisos (inspirada en el LLMSecurityAnalyzer de OpenHands).
Cuando está habilitada, cada schema de herramienta gana un campo obligatorio security_risk
(LOW / MEDIUM / HIGH) que el modelo completa como parte del mismo call — sin ninguna
llamada extra al LLM. Los calls calificados en confirm_at o más alto pausan y piden tu
confirmación en la superficie activa (diálogo web, Telegram); un call rechazado vuelve al modelo
como una observación de error para que re-planifique.
"super_agent": { "security_risk": { "enabled": true, "confirm_at": "HIGH", "confirm_unknown": true }}confirm_at— calificación mínima que pausa (LOWconfirma todo,HIGHsolo acciones destructivas o hacia afuera).confirm_unknown— también pausa cuando el modelo no calificó el call (los modelos débiles a veces omiten el campo).
No es un duplicado del modo de permisos — filtra por otro eje. El modo de permisos decide por identidad de la tool (¿es peligrosa / está en la allowlist?); el analizador de riesgo decide por el juicio del modelo sobre la gravedad de esta acción concreta. Por eso agrega una barrera que el modo de permisos no puede dar:
- En
automaticola calificación de riesgo reemplaza la confirmación estática por herramienta peligrosa. - En
permisola allowlist sigue aplicando y el gate de riesgo se compone encima. - En
totalse vuelve un piso de seguridad: todo corre libre excepto una acción calificadaHIGH, que igual se detiene para confirmación aun con confianza total. Ese es el punto — una acción catastrófica se atrapa por más que confíes en el agente.
Judge de completitud
Sección titulada «Judge de completitud»Loop de verificación (patrón critic de OpenHands): un LLM juez puntúa la probabilidad de que el
pedido original esté completamente satisfecho. Por debajo de success_threshold, el agente
recibe una nota interna de verificación (qué parece faltar, según el juez) y sigue trabajando —
hasta max_iterations rondas. Un juez inutilizable (engine caído, respuesta no parseable) acepta
el resultado en vez de bloquearlo.
Cubre dos formas distintas de que un turno termine antes de tiempo:
enabled(opt-in) — un turno con completion contract (superficies de código) declaró que terminó, y el juez verifica esa declaración.continue_unfinished(activado por defecto) — un turno conversacional (Telegram, chat web) dejó de llamar herramientas. Eso es también lo que hace un modelo cuando solo anuncia el paso siguiente (“ahora genero el SRT en inglés”) y no escribe ninguna llamada: la tarea queda a mitad esperando que la empujen. El juez es ese empujón. Un turno que no usó herramientas nunca se juzga (una charla no tiene nada que terminar), ni tampoco uno que cerró preguntándote algo — ese está esperando, no inconcluso. “Preguntándote algo” cubre las dos formas de preguntar: la herramientaask_questionsy el paso de cierre reservado, ese que se queda sin presupuesto de herramientas y te ofrece seguir. Continuar ese turno es responder por vos, y como la ronda siguiente choca contra la misma pared, termina repitiendo el mismo resumen y la misma pregunta.
Los agentes de proyecto también pasan por acá, no solo el super-agente — por la mitad
continue_unfinished nada más, porque nunca toman el camino del completion contract. Aplica en
todos los canales en los que responde un agente de proyecto, no solo en los que mirás:
anunciar el paso siguiente en vez de darlo es una falla del modelo, no de la superficie. Las dos
exclusiones de arriba son las que mantienen bajo el costo — después de ellas, los únicos turnos
que se juzgan son los que usaron herramientas de verdad y después se quedaron callados sin
preguntar nada, o sea una llamada extra al modelo por un turno que si no se quedaba ahí hasta que
escribieras “seguí”.
"super_agent": { "judge": { "enabled": true, "continue_unfinished": true, "success_threshold": 0.6, "max_iterations": 2, "model": "" }}model vacío → el juez corre sobre super_agent.model y, si no hay, sobre el modelo con el que
corrió el turno — así un agente de proyecto se juzga igual en una instalación que nunca configuró
un super-agente. Poné un modelo barato para mantener bajo el overhead de verificación. Los veredictos salen como eventos judge_verdict, en el resultado
como result.judge, y en el mensaje de Telegram que cerró el turno — así un turno que se hizo
largo se puede rastrear hasta el veredicto que lo mantuvo andando.
max_iterations limita cuántas veces el juez puede devolver un turno — no multiplica lo que
el turno puede gastar. Las rondas comparten el presupuesto de herramientas de la superficie
con la corrida que vino antes: cada una recibe lo que quedó, y cuando queda muy poco para que una
ronda valga la pena (un paso de acción más el paso de cierre reservado) el loop frena ahí y emite
judge_budget_exhausted en vez de arrancarla. Así un mensaje en el chat web cuesta como mucho
web_max_iters, no (1 + max_iterations) × web_max_iters.
Presupuesto de herramientas por superficie
Sección titulada «Presupuesto de herramientas por superficie»Cuántos pasos de herramienta puede dar un turno depende de si podés mirarlo trabajar — y se
decide por superficie, no por quién contesta. Un agente de proyecto en el chat web tiene el
mismo presupuesto que Roby; un chat que mirás es un chat que mirás. (Las cuatro perillas viven bajo
super_agent porque ahí viven todos los presupuestos del tool loop, incluido el de rutinas, que
gobierna agentes de proyecto.)
| Superficie | Presupuesto | Por qué |
|---|---|---|
| Telegram | telegram_max_iters (1000) | Inicio de cada tool queda visible y Telegram mantiene indicador escribiendo, así turno normalmente corre hasta terminar. |
| Chat web + sidebar | web_max_iters (1000) | Cada llamada se dibuja en vivo y estás a un click de frenarlo — la baranda sos vos, así que el turno corre hasta terminar el trabajo. |
apx exec | cli_max_iters (40) | Da lugar para pasarle trabajo al agente de un proyecto y verificarlo; tiene tope porque también lo usan scripts y otros agentes. Desde apx exec, pasarle trabajo a otro agente espera la respuesta en vez de quedar en segundo plano. |
| Rutinas (sin Telegram) | routine_max_iters (1000) | Nadie está esperando a mitad de la corrida para contestar “¿sigo?”. |
| Salas grupales | group_max_iters (50) | La única superficie donde un mensaje se abre en varios — ver abajo. |
| Superficies de código | Explícito, más el completion contract | Frenan en finish, no en un número. |
Cada número es el presupuesto de un turno, no de una pasada del tool loop: si el judge de completitud devuelve el turno para terminar algo, esas rondas gastan lo que queda del mismo número en vez de recibirlo de nuevo entero.
Los tres techos de 1000 son frenos de emergencia, no puntos de parada normales: el loop ya
termina en cuanto el modelo deja de llamar herramientas, y la detección de loops aborta las
repeticiones. Poné cualquiera en 0 para usar el valor por defecto.
Una sala grupal se mira y se frena igual que el chat web, así que por la regla de superficie le tocaría el mismo techo — pero una línea tuya puede encadenar hasta diez respuestas de agentes, cada una un tool loop completo. Darle a cada orador el techo del 1:1 haría, sin que nadie lo decida, que un mensaje valga por diez. Entonces cada orador recibe una porción: espacio real para trabajo de varios pasos, y los diez juntos siguen costando no más que un turno en tu chat 1:1 con cualquiera de ellos. Mismo principio que las rondas del juez de arriba — el presupuesto es de tu turno, y todo lo que se desprende de él entra adentro. Un orador que se queda sin presupuesto cierra contando hasta dónde llegó y la sala sigue; el trabajo solitario que necesita cientos de pasos va en el chat propio de ese agente, que tiene el techo para eso.
"super_agent": { "telegram_max_iters": 0, "web_max_iters": 0, "routine_max_iters": 0, "group_max_iters": 0}Cuando un presupuesto sí se agota, el último paso queda reservado para un mensaje de cierre sin herramientas, escrito por modelo: qué hizo, qué falta y si querés que siga. Con techos de ejecución hasta terminar, eso queda como piso raro de seguridad, no cierre normal.
Detección de loops (stuck detection)
Sección titulada «Detección de loops (stuck detection)»El tool loop vigila dos formas de quedarse trabado: el mismo call devolviendo el mismo resultado
action_repeat veces, y el mismo call fallando error_repeat veces seguidas. En la primera
detección el modelo recibe una nota in-band (“parecés trabado — cambiá de enfoque o explicá el
bloqueo”); si sigue loopeando, el turno se cierra antes con un wrap-up escrito por el modelo en
vez de quemar el resto del presupuesto de iteraciones. Activado por defecto:
"super_agent": { "stuck_detection": { "enabled": true, "action_repeat": 4, "error_repeat": 3 }}Fallback de modelo
Sección titulada «Fallback de modelo»Si el modelo primario no está disponible, APX recorre una lista ordenada y configurable de proveedores de fallback. Configurá el orden y habilitá el router:
apx model enableapx model order ollama openrouter groqapx model status # prueba todos los proveedores; muestra cuál se usaría ahoraMirá Configuration para el schema completo de super_agent.model_fallback.
Routing por contenido
Sección titulada «Routing por contenido»Encima de la cadena estática de fallback, reglas opt-in de routing por turno (inspiradas en el
RouterLLM de OpenHands) inspeccionan el mensaje real — imágenes, tamaño del prompt/contexto,
canal, keywords — y prefieren otro modelo para ese turno. Las reglas se evalúan en orden; gana la
primera que matchea completa. El modelo preferido igual pasa por el health-check y cae por la
cadena normal si no está disponible, y un override explícito por request siempre le gana a las
reglas.
"super_agent": { "routing": { "enabled": true, "rules": [ { "model": "anthropic:claude-sonnet-5", "when": { "has_image": true } }, { "model": "groq:llama-3.3-70b-versatile", "when": { "max_prompt_chars": 200, "channels": ["telegram"] } }, { "model": "anthropic:claude-opus-4-8", "when": { "keywords": ["refactor", "arquitectura"] } } ] }}Condiciones de when (todas deben cumplirse): has_image, min_prompt_chars /
max_prompt_chars, min_context_chars, channels (lista), keywords (lista, substring
case-insensitive). Un when vacío matchea todos los turnos — útil como catch-all final.
Siguiente
Sección titulada «Siguiente»- Memory system — cómo el agente recupera contexto relevante entre canales.
- Routines — programá el super-agent o un
exec_agentsimple en un cron. - Configuration — referencia completa de
super_agent.*eidentity.json.