Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/geremyjampiersalasgarcia-eng/Caso_Practico_Semillero_IA/llms.txt

Use this file to discover all available pages before exploring further.

The Action Agent (agente_accion) is the only write-capable agent in the system. While all other agents are read-only RAG responders, agente_accion uses LangChain’s @tool decorator and bind_tools() to give Gemini the ability to call a Python function — registrar_oportunidad_crm — that writes the opportunity record to both backend/data/registro_oportunidades.txt and the PostgreSQL oportunidades table. A server-side sandboxing layer ensures the tool is never executed without an explicit confirmation=True signal from the user, preventing the LLM from writing data autonomously.

When it triggers

The orchestrator routes to agente_accion under any of these conditions:
  • The intent classifier returns accion_registro.
  • The user sends a short confirmation text such as “sí”, “confirmar”, “sí, registrar”, or similar.
  • The last assistant message in the conversation history contains the phrase 'registrar la oportunidad' or 'para continuar', indicating a pending confirmation flow.

Required fields

Before calling the registrar_oportunidad_crm tool, the agent validates that all eight required fields are present. If any are missing, the agent asks the user for them instead of proceeding:
#Field (tool parameter)Notes
1clienteCompany or person name
2contactoName of the contact person
3productoPatito S.A. product name
4cantidadNumber of units (int)
5precio_con_descuentoUnit price after discount applied (float)
6porcentaje_descuentoApplied discount percentage, e.g. 8.0 (0 if none)
7condicion_pagocontado or crédito (if credit: 30, 60, or 90 days)
8monto_totalcantidad × precio_con_descuento (float)
The LLM calculates precio_con_descuento and monto_total from the data provided by the user before presenting the confirmation summary and before invoking the tool.

Multi-step conversation flow

1

User submits initial registration request

The user sends a natural-language message describing the opportunity, for example:
Registra una oportunidad: cliente Comercial ABC, 10 unidades de
Patito Pro 2026, 8% de descuento, pago de contado.
The orchestrator classifies this as accion_registro and routes to agente_accion.
2

Agent validates fields and asks for missing data

The agent checks the message against the eight required fields. If any are absent, it responds with a targeted question — for example:
Para completar el registro, necesito los siguientes datos:
- ¿Cuál es el nombre del contacto?
- ¿Cuál es el precio unitario original (antes del descuento)?
The LLM is not allowed to call the tool at this stage, even if it believes all data is present.
3

Agent presents summary with calculated totals

Once all fields are collected, the agent calculates the derived values and presents a Markdown summary for review:
CampoValor
ClienteComercial ABC
ContactoGeremy
ProductoPatito Pro 2026
Cantidad10
Descuento8%
Precio con descuentoUSD 1,195.08
Monto totalUSD 11,950.80
Condición de pagoContado
4

User confirms

The user responds with an explicit confirmation: “Sí, registrar”, “Confirmar”, or equivalent. The frontend sets confirmation: true in the next POST /api/v1/chat payload.
5

Agent executes registrar_oportunidad_crm tool

With confirmation=True verified server-side, the agent invokes the LangChain tool:
tool_output = registrar_oportunidad_crm.invoke(tool_call["args"])
The tool writes a delimited record to registro_oportunidades.txt and inserts a row into the PostgreSQL oportunidades table simultaneously.
6

Agent returns the opportunity ID

The final response confirms success and returns the generated opportunity identifier:
✅ Proceso de registro finalizado.

Resultado del CRM: Registro guardado con éxito (TXT y Base de Datos).
El identificador es: OPP-20260706-A3F2B1
The ID format is OPP-YYYYMMDD-XXXXXX where the last six characters are the first six hex digits of a random UUID.

Discount authorization

If the discount percentage provided by the user exceeds 10%, the agent will warn that commercial manager approval is required before the opportunity can be registered. If the discount exceeds 20%, director-level approval is required. Discounts above 30% are not permitted. The agent includes this warning in the confirmation summary and will not suppress it even if the user asks it to. This rule is sourced from the same commercial-policies knowledge base used by agente_politicas.

Example requests

The following conversation starters all trigger agente_accion: 1. Full data in one message
Registra una oportunidad: cliente Comercial ABC, 10 unidades de Patito Pro 2026,
8% de descuento, pago de contado.
(The agent will ask for the contact name and unit price before proceeding.) 2. Partial data — agent will ask follow-up questions
Quiero registrar una venta para la Empresa XYZ. Van a comprar 5 unidades a
$50 dólares cada una con pago a crédito de 30 días.
(Missing: contact name, product name, discount percentage.) 3. Minimal data — maximum clarifying questions
Guarda en el CRM una oportunidad para el cliente Hospital San José,
el contacto es María, son 20 licencias.
(Missing: product name, unit price with discount, discount percentage, payment condition.)

The registrar_oportunidad_crm LangChain tool

The tool is defined with the @tool decorator from langchain_core.tools and bound to the LLM via bind_tools():
from langchain_core.tools import tool

@tool
def registrar_oportunidad_crm(
    cliente: str,
    contacto: str,
    producto: str,
    cantidad: int,
    precio_con_descuento: float,
    porcentaje_descuento: float,
    condicion_pago: str,
    monto_total: float,
) -> str:
    """Registra de manera definitiva la oportunidad en el sistema CRM (archivo de texto).
    EJECUTA ESTA HERRAMIENTA ÚNICAMENTE DESPUÉS DE QUE EL USUARIO HAYA CONFIRMADO EL RESUMEN.
    """
    # Generates OPP-YYYYMMDD-XXXXXX ID
    now = datetime.now()
    opp_id = f"OPP-{now.strftime('%Y%m%d')}-{uuid.uuid4().hex[:6].upper()}"
    ...

# Bound to the LLM inside AccionAgent.process_query:
llm_with_tools = get_llm().bind_tools([registrar_oportunidad_crm])
The tool includes a duplicate-detection check (_es_duplicado) that scans registro_oportunidades.txt for an existing entry with the same client and product combination before writing.

Output files

Confirmed opportunities are persisted in two places simultaneously:
DestinationPath / TableFormat
Text filebackend/data/registro_oportunidades.txtDelimited plain-text blocks separated by = lines, one block per opportunity
PostgreSQLoportunidades tableStructured relational row with all fields including id, fecha, estado
The text file is created automatically on first write. The PostgreSQL row is inserted in the same function call; if the database write fails, the error is logged but the TXT write is still committed (and vice versa), providing basic redundancy.

Build docs developers (and LLMs) love