LIDR Academy Estimator

Flujo de agentes (S13)

El pipeline de estimación reexpresado como un grafo LangGraph: una estado compartido tipado que fluye por agentes especializados. Dos handovers explícitos (Command(goto)), dos gates humanos (interrupt() + resume) y un fan-out (Send) que estima cada tarea en paralelo. Recurso de solo lectura — no ejecuta nada.

Command(goto) handover: un agente pasa el control a otro sin arista estática.
interrupt() gate humano: el grafo pausa y espera un resume con la decisión.
Send fan-out: una rama en paralelo por tarea; convergen en un join.
conditional arista condicional: enruta a proposal o a END según el estado.
START
🕶
Morpheus agente
Classifier · «Te mostraré hasta dónde llega la madriguera»
gpt-4o-mini
classifier_agent() · GRAPH_CLASSIFIER_MODEL

Clasifica la complejidad y reformula el brief.

Lee la transcripción cruda y produce una ComplexityClassification: una etiqueta de complejidad (low / medium / high) y un brief reformulado y limpio. La complejidad decide luego el reasoning effort del agente de estructura. Es el nodo de entrada y hace el primer handover (Command(goto) → structure), sin arista estática.

↓ Command(goto=…)
handover explícito — sin arista estática
🥋
Neo agente
Structure · «Yo sé kung-fu — veo la estructura»
gpt-5
structure_agent() · AGENT_MODEL

Descompone el brief en módulos → tareas (sin horas).

Reutiliza el agente hecho a mano de la S12 (bucle Responses API) para convertir el brief en un árbol de módulos y tareas, todavía sin horas. El esfuerzo de razonamiento se elige según la complejidad del classifier (GRAPH_STRUCTURE_EFFORT_BY_COMPLEXITY).

↓ arista estática
🧑
El Operador gate humano
🧑 Gate 1 · revisión de estructura · «Tú tomas la decisión»
sin LLM
human_gate_structure()

Pausa para revisión humana de los módulos y tareas.

Human-in-the-loop: interrupt() detiene el grafo y expone la estructura para que una persona la edite o apruebe. Al reanudar (Command(resume=…)) devuelve los módulos aprobados. Disciplina interrupt-first: no escribe en el estado antes de pausar, porque el resume re-ejecuta el nodo entero.

pausa interrupt() — reanuda con Command(resume=…)
↓ Send · fan-out
una rama en paralelo por cada tarea aprobada
🎛
Tank fan-out
Hours ×N · «Cargo los programas que hagan falta, en paralelo»
sin LLM
estimate_task_hours() · TASK_HOURS_TOP_K / TASK_HOURS_DISTANCE_THRESHOLD

Horas por tarea vía búsqueda vectorial determinista.

No usa LLM: es un fan-out con la Send API (una rama en paralelo por cada tarea aprobada). Cada rama busca las tareas históricas más cercanas y deriva las horas por consenso ponderado por distancia (reutiliza la lógica de la S10). Sin análogo por debajo del umbral → tarea marcada en rojo.

↓ join · N → 1
las ramas convergen en el mismo super-step
🏍
Trinity join
Recover & handover · «Rescato lo que se dio por perdido»
gpt-5
recover_and_handover() · AGENT_MODEL

Junta las ramas, recupera tareas dudosas y construye la estimación.

Nodo de join del fan-out. Detecta tareas dudosas (sin match, rango contradictorio o fiabilidad baja) y, si las hay, lanza un bucle agéntico de recuperación (S12). Fusiona las horas y construye el Estimate consolidado. Termina con el segundo handover (Command(goto) → analysis).

↓ Command(goto=…)
handover explícito — sin arista estática
🔮
El Oráculo agente
Analysis · «Te diré la verdad, aunque no guste»
gpt-4o
analysis_agent() · GRAPH_ANALYSIS_MODEL

Redacta el informe de fiabilidad (no toca los números).

Lee la estimación y escribe un ReliabilityReport: confianza global, ratio de tareas fundamentadas (calculado de forma determinista, sobrescribe el del LLM), puntos débiles y un resumen. No modifica ninguna cifra; solo evalúa.

↓ arista estática
🧑
El Operador gate humano
🧑 Gate 2 · validación final · «Tú tomas la decisión»
sin LLM
human_gate_analysis()

Pausa para la validación humana del informe y la estimación.

Segundo human-in-the-loop: interrupt() expone la estimación y el informe de fiabilidad. Al reanudar, aplica los overrides, fija el status (validated / needs_review) y registra si se pidió una propuesta comercial (want_proposal).

pausa interrupt() — reanuda con Command(resume=…)
↓ arista condicional
→ proposal si GRAPH_PROPOSAL_ENABLED + want_proposal · si no → END
📐
El Arquitecto agente
Proposal · «Compongo el constructo final»
gpt-4o
proposal_agent() · GRAPH_PROPOSAL_MODEL

Bonus: redacta la propuesta comercial.

Nodo condicional: solo se ejecuta si GRAPH_PROPOSAL_ENABLED está activo Y el humano pidió propuesta en el gate 2. Redacta una CommercialProposal en markdown, anclada estrictamente a la estimación validada. En caso contrario, el grafo termina en END.

↓ END
END