# Guia Tecnica Flow Standard V1

Documento tecnico y operativo del formato de flujos V1 que hoy usa Medusa.

Complementa:
- [FLOW_STANDARD_V1.md](/c:/Apache24/htdocs/sidelink/backend/IA/FLOW_STANDARD_V1.md)
- [FLUJOS.md](/c:/Apache24/htdocs/sidelink/backend/IA/FLUJOS.md)

## Objetivo

Esta guia explica:
- que representa cada parte del flujo
- que campos soporta el runtime actual
- que garantiza hoy el backend
- que limitaciones existen todavia
- como escribir flujos V1 sin ambiguedad

## Estado actual del sistema

Hoy el sistema funciona asi:

1. El core detecta intencion y slots desde lenguaje natural.
2. El backend mantiene el estado conversacional.
3. El runtime de flujo decide el siguiente paso deterministico.
4. GPT redacta la respuesta final al cliente.
5. Las tools reales se ejecutan desde backend.

Regla central:
- la IA entiende y redacta
- el runtime decide
- el backend ejecuta

## Donde se guarda un flujo

Un flujo V1 se guarda en la tabla `ia_prompts`.

Convenciones:
- `clave` en DB: debe empezar con `flujo_`
- `content`: JSON valido
- `estado`: `1` activo, `0` inactivo

Ejemplo:
- `clave = flujo_soporte`
- `id` interno del JSON = `flujo_soporte_v1`

## Activacion de flujos

Un flujo V1 solo se carga si:
- su `clave` fue derivada desde la intencion
- y en DB tiene `estado = 1` o `estado IS NULL`

Si el flujo esta inactivo:
- no entra en `contexto.flujos_config`
- no participa del runtime
- pero la sesion puede seguir teniendo `slotsActuales` viejos de ese namespace

Eso significa:
- `slotsActuales.flujo_soporte` no prueba que el flujo este activo
- el trace correcto es `flows.lookup.cantidadCargados`

## Estructura raiz obligatoria

Formato recomendado:

```json
{
  "id": "flujo_soporte_v1",
  "version": 1,
  "nombre": "Soporte tecnico",
  "intent_principal": "prompt_soporte",
  "settings": {
    "entry_step": "pedir_dni"
  },
  "tool_permissions": {
    "buscar_cliente": true,
    "transferir_operador": true,
    "registrar_compromiso_pago": false
  },
  "slots": {},
  "backend_facts": {},
  "steps": []
}
```

Campos:
- `id`: identificador tecnico del flujo
- `version`: hoy debe ser `1`
- `nombre`: nombre visible para humanos
- `intent_principal`: prompt que normalmente dispara este flujo
- `settings.entry_step`: primer paso del flujo
- `tool_permissions`: tools habilitadas o bloqueadas por el flujo
- `slots`: datos conversacionales
- `backend_facts`: hechos confirmados por backend
- `steps`: pasos ejecutables por runtime

## Tool permissions

Claves soportadas hoy:
- `buscar_cliente`
- `transferir_operador`
- `registrar_compromiso_pago`

Valores:
- `true`
- `false`

Regla de merge actual:
- si algun flujo activo marca una tool en `false`, gana `false`
- `true` solo habilita si ningun flujo activo la bloqueo

Ejemplo:

```json
{
  "tool_permissions": {
    "buscar_cliente": false
  }
}
```

Uso tipico:
- soporte: suele permitir `buscar_cliente`
- ventas: suele bloquear `buscar_cliente`

## Slots

Los `slots` son datos que el cliente dice o confirma durante la conversacion.

Ejemplos:
- `dni_cuit`
- `localidad`
- `tipo_problema`
- `resultado_final`

Formato:

```json
{
  "dni_cuit": {
    "type": "text",
    "required": true,
    "label": "DNI o CUIT",
    "description": "Documento informado por el cliente para validar la cuenta"
  }
}
```

Campos permitidos:
- `type`
- `required`
- `label`
- `description`
- `values`

Tipos soportados:
- `text`
- `enum`
- `boolean`

Buenas practicas:
- usar nombres cortos en snake_case
- usar `enum` cuando queres un conjunto cerrado
- usar `label` y `description` para que la UI y otra IA entiendan el dato

## Backend facts

Los `backend_facts` son hechos que no debe inventar el cliente.

Ejemplos conceptuales:
- `cliente_verificado`
- `dni_validado`
- `estado_administrativo`
- `conexion_estado`

Formato:

```json
{
  "estado_administrativo": {
    "type": "enum",
    "label": "Estado administrativo",
    "description": "Estado del servicio informado por backend",
    "values": ["activo", "cortado_falta_pago", "suspendido", "desconocido"]
  }
}
```

Importante:
- declarar un `backend_fact` en el flujo no significa que hoy todos los providers lo llenen
- solo documenta que el flujo espera ese dato

Hoy los facts realmente confiables en runtime son:
- `cliente_verificado`
- `dni_validado`

Facts como `estado_administrativo` pueden declararse ya en el flujo, pero su llenado real depende de la normalizacion backend/provider.

## Tipos de steps

V1 soporta:
- `question`
- `message`
- `action`
- `branch`
- `end`

### `question`

Pide o confirma un dato del cliente.

```json
{
  "id": "pedir_dni",
  "type": "question",
  "slot": "dni_cuit",
  "message": "Pedir DNI o CUIT para verificar la cuenta.",
  "next_step": "validar_cliente"
}
```

Campos:
- `id`
- `type`
- `slot`
- `message`
- `next_step`

Reglas:
- `slot` debe existir en `slots`
- `message` no es texto final al cliente
- GPT redacta el mensaje real a partir de esta instruccion

### `message`

Informa algo y luego sigue.

```json
{
  "id": "cliente_no_encontrado",
  "type": "message",
  "message": "Pedir otro DNI o CUIT porque no se pudo validar la cuenta.",
  "next_step": "pedir_dni"
}
```

Campos:
- `id`
- `type`
- `message`
- `next_step`

### `action`

Ejecuta una tool backend.

```json
{
  "id": "validar_cliente",
  "type": "action",
  "action": "buscar_cliente",
  "requires": ["dni_cuit"],
  "on_success": "evaluar_estado_admin",
  "on_failure": "cliente_no_encontrado"
}
```

Campos:
- `id`
- `type`
- `action`
- `requires`
- `params`
- `on_success`
- `on_failure`

Actions soportadas hoy:
- `buscar_cliente`
- `transferir_operador`
- `registrar_compromiso_pago`

`requires` puede apuntar a:
- slots
- backend_facts

`params` se usa para datos de la tool:

```json
{
  "params": {
    "area": "cobranza",
    "motivo": "Servicio cortado por falta de pago"
  }
}
```

### `branch`

Evalua condiciones y decide a que paso ir.

```json
{
  "id": "evaluar_estado_admin",
  "type": "branch",
  "branches": [
    {
      "when": {
        "fact": "estado_administrativo",
        "equals": "cortado_falta_pago"
      },
      "go_to": "derivar_cobranza_corte"
    },
    {
      "when": {
        "fact": "estado_administrativo",
        "equals": "activo"
      },
      "go_to": "pedir_tipo_problema"
    }
  ],
  "default_next": "pedir_tipo_problema"
}
```

Cada rama tiene:
- `when`
- `go_to`

`when` soporta:
- `slot`
- `fact`
- `equals`
- `not_equals`
- `exists`

Reglas:
- cada rama debe apuntar a un solo `slot` o un solo `fact`
- `default_next` sirve como fallback si ninguna rama coincide

### `end`

Marca fin del flujo.

```json
{
  "id": "fin",
  "type": "end"
}
```

## Relaciones validas entre nodos

Semantica correcta:
- `question` -> `next_step`
- `message` -> `next_step`
- `action` -> `on_success` y/o `on_failure`
- `branch` -> `branches[].go_to` y/o `default_next`
- `end` -> no sale a ningun lado

Eso es importante porque las conexiones del canvas no son lineas libres: representan una de estas relaciones concretas.

## Que valida hoy el editor

La UI hoy valida:
- que la clave empiece con `flujo_`
- que exista `id`, `nombre`, `intent_principal`
- que exista `entry_step`
- que existan `steps`
- ids duplicados
- `slot` inexistente
- `next_step` inexistente
- `on_success` / `on_failure` inexistentes
- `go_to` inexistentes
- `default_next` inexistente
- `requires` que no existen en `slots` ni `backend_facts`
- `backend_facts` usados en `branch` pero no declarados

Importante:
- algunas cosas salen como `warning`, no como `error`
- un warning no siempre bloquea guardar

## Que garantiza hoy el runtime

El runtime V1 hoy ya puede:
- cargar un flujo V1
- resolver `entry_step`
- seguir `next_step`
- ejecutar `action`
- usar `on_success` y `on_failure`
- evaluar `branch`
- seguir `default_next`
- continuar un flujo despues de una tool si la transicion es deterministica

## Que no conviene hacer

No conviene:
- inventar campos fuera del standard
- mezclar estructura legacy con V1
- usar nombres ambiguos como `step1`, `dato1`, `respuesta`
- usar `backend_facts` no declarados
- poner textos finales al cliente en `message` como si fueran copy definitivo

`message` es una instruccion del runtime, no el mensaje final que sale por WhatsApp.

## Recomendaciones de modelado

Para un flujo sano:

1. Separar identificacion de diagnostico o cierre.
2. Usar `action` para validaciones reales.
3. Usar `branch` cuando la decision depende de un valor concreto.
4. Usar `question` solo para capturar o confirmar datos.
5. Terminar siempre en un `end`.

## Ejemplo minimo

```json
{
  "id": "flujo_ventas_v1",
  "version": 1,
  "nombre": "Ventas",
  "intent_principal": "prompt_ventas",
  "settings": {
    "entry_step": "pedir_localidad"
  },
  "tool_permissions": {
    "buscar_cliente": false,
    "transferir_operador": true
  },
  "slots": {
    "localidad": {
      "type": "text",
      "required": true,
      "label": "Localidad"
    },
    "dni": {
      "type": "text",
      "required": true,
      "label": "DNI"
    }
  },
  "backend_facts": {},
  "steps": [
    {
      "id": "pedir_localidad",
      "type": "question",
      "slot": "localidad",
      "message": "Preguntar en que localidad quiere contratar el servicio.",
      "next_step": "pedir_dni"
    },
    {
      "id": "pedir_dni",
      "type": "question",
      "slot": "dni",
      "message": "Pedir el DNI del interesado.",
      "next_step": "derivar_ventas"
    },
    {
      "id": "derivar_ventas",
      "type": "action",
      "action": "transferir_operador",
      "requires": ["localidad", "dni"],
      "params": {
        "area": "ventas",
        "motivo": "Lead de ventas completo"
      },
      "on_success": "fin",
      "on_failure": "fin"
    },
    {
      "id": "fin",
      "type": "end"
    }
  ]
}
```

## Checklist antes de guardar

- la clave empieza con `flujo_`
- `id`, `nombre`, `intent_principal` estan completos
- `entry_step` existe y apunta a un step real
- cada step tiene `id` unico
- todos los targets existen
- los slots usados en `question` existen
- los facts usados en `branch` estan declarados
- `end` existe
- `tool_permissions` reflejan el comportamiento esperado

