Files
fn_registry/python/functions/infra/summarize_fleet_transitions.md
T
agent 118d5d36d3 feat(orquestador): feed reactivo FLEET-STATE + fix peek de drain_fleet_events
El orquestador no se enteraba de los cambios de estado de su flota: el drenado
era manual y el peek documentado `./fn run drain_fleet_events --advance false`
devolvia un falso `{total_new:0, cursor:0}` porque `fn run` mapea los argumentos
posicionalmente y no parsea flags `--nombre valor` (events_path acababa valiendo
"--advance", una ruta inexistente).

- drain_fleet_events: nuevo helper _normalize_fn_run_flags que renormaliza el
  patron `--advance <bool>` aplanado por `fn run`, de modo que el peek funciona
  directo desde la CLI sin tocar el runner de Go. Bump 1.1.0 + growth log + tests
  del normalizador (unit y end-to-end por HOME).
- summarize_fleet_transitions (nueva, pure, grupo claude-fleet): resume el dict
  by_classification de drain en un bloque de una linea con las tres categorias
  accionables (terminados / reclaman / estancados), dedup por session_id y
  truncado de objetivo.
- hook_fleet_state_inject.sh (UserPromptSubmit): si la sesion es role=orchestrator
  (leido de ~/.claude/goals/<session_id>.json), hace peek de la cola sin mover el
  cursor y emite el bloque FLEET-STATE cada turno. Degrada limpio si el watcher
  esta caido, la cola no existe o la sesion no es orquestador.

El registro del hook va en .claude/settings.local.json (gitignored, fuera de este
commit). Pendiente, lo integra otro agente: documentar el bloque FLEET-STATE en
.claude/commands/orquestador.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 00:06:01 +02:00

4.6 KiB

name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, params, output, tested, tests, test_file_path, file_path
name kind lang domain version purity signature description tags uses_functions uses_types returns returns_optional error_type imports params output tested tests test_file_path file_path
summarize_fleet_transitions function py infra 1.0.0 pure def summarize_fleet_transitions(by_classification: dict, max_items: int = 6) -> str Resume en una sola linea las transiciones accionables de la flota de Claudes para inyectar por un hook UserPromptSubmit al orquestador. Toma el dict by_classification de drain_fleet_events (agrupado por campo `to`) y condensa SOLO las tres categorias accionables: DICE_TERMINADO (terminados), RECLAMA (reclaman) y ESTANCADO (estancados); ignora TRABAJANDO, GONE y MAL_LANZADO. Funcion pura, determinista y defensiva: deduplica por session_id, trunca el goal y limita el total con overflow `(+N mas)`.
orchestration
claude-fleet
fleet
summary
hook
orchestrator
false
name desc
by_classification dict agrupado por campo `to` tal como lo devuelve drain_fleet_events. Solo se leen las claves accionables DICE_TERMINADO, RECLAMA y ESTANCADO; cada valor es una lista de eventos (dicts) con al menos session_id (str UUID), goal (str) y to (str). Puede ser None o {} (devuelve 'sin cambios').
name desc
max_items limite total de eventos mostrados sumando las tres categorias (default 6). Al superarse se trunca y se añade ' (+N mas)'. El cupo se llena en orden de categorias terminados -> reclaman -> estancados.
una cadena de UNA sola linea. 'FLEET-STATE: sin cambios' si no hay nada accionable; en caso contrario 'FLEET-STATE: terminados=[<sid8>:<goal>] reclaman=[...] estancados=[...] (+N mas) (drain con ./fn run drain_fleet_events para consumir)' omitiendo las categorias vacias. true
test_golden_tres_categorias_con_datos
test_categorias_vacias_sin_cambios
test_solo_no_accionables_sin_cambios
test_dedup_por_session_id_se_queda_ultima
test_truncado_de_goal_mayor_de_40
test_max_items_con_overflow
test_entrada_none_sin_cambios
test_entrada_dict_vacio_sin_cambios
test_valor_no_lista_se_salta
test_eventos_no_dict_se_saltan
test_session_id_ausente_usa_placeholder
test_goal_ausente_usa_placeholder
test_omite_categorias_vacias_solo_renderiza_con_datos
test_varios_eventos_misma_categoria_separados_por_coma
python/functions/infra/summarize_fleet_transitions_test.py python/functions/infra/summarize_fleet_transitions.py

Ejemplo

from summarize_fleet_transitions import summarize_fleet_transitions

by_classification = {
    "DICE_TERMINADO": [
        {"session_id": "a1b2c3d4-aaaa-bbbb", "goal": "Migrar tabla salesforce a europe-west1", "to": "DICE_TERMINADO"},
    ],
    "RECLAMA": [
        {"session_id": "e5f6g7h8-cccc-dddd", "goal": "Necesito clave API de Metabase", "to": "RECLAMA", "urgent": True},
    ],
    "ESTANCADO": [],
    "TRABAJANDO": [
        {"session_id": "99887766-eeee-ffff", "goal": "Indexando registry", "to": "TRABAJANDO"},
    ],
}

linea = summarize_fleet_transitions(by_classification)
# FLEET-STATE: terminados=[a1b2c3d4:Migrar tabla salesforce a europe-w…] reclaman=[e5f6g7h8:Necesito clave API de Metabase] (drain con ./fn run drain_fleet_events para consumir)
print(linea)

Cuando usarla

Cuando un hook (tipico UserPromptSubmit) necesita resumir en una sola linea las transiciones pendientes de la flota para inyectarlas al orquestador-Claude. Se encadena despues de drain_fleet_events (que produce el by_classification) para darle al orquestador, sin coste de lectura extra, el estado accionable de un vistazo: quien dice haber terminado, quien reclama atencion y quien esta estancado.

Gotchas

  • Dedup por session_id: dentro de cada categoria, si un mismo session_id aparece en varios eventos se conserva solo la ultima aparicion (la transicion mas reciente en la lista). Eventos sin session_id valido no se deduplican entre si y cada uno cuenta como entrada propia.
  • Truncado de goal: el goal se recorta a 40 caracteres con elipsis ; un goal ausente o vacio se muestra como (sin objetivo) y un session_id ausente/vacio como ????????.
  • Solo categorias accionables: TRABAJANDO, GONE y MAL_LANZADO se ignoran a proposito. Si las tres categorias accionables estan vacias o no existen, devuelve FLEET-STATE: sin cambios.
  • Reparto de max_items: el cupo total se llena recorriendo las categorias en orden (terminados -> reclaman -> estancados); los sobrantes se cuentan en (+N mas). Es defensiva ante datos mal formados (valores no-lista o eventos no-dict se omiten sin lanzar excepcion).