# Funciones de código (VPower)

Las **funciones de código** permiten que tu agente de voz ⚡ VPower ejecute JavaScript propio durante la llamada: consultar tu sistema, validar datos, reservar un turno, calcular un precio… sin tener que montar ni mantener un servidor.

El agente decide cuándo usar cada función y le pasa los **parámetros** que necesita (por ejemplo, el DNI que dijo la persona). Tu código hace el trabajo y devuelve un resultado, que el agente usa para seguir la conversación.

> 💡 Si tu lógica ya vive en un servidor tuyo, usa una **Función personalizada (webhook)**. Las funciones de código son para cuando quieres que la lógica corra en Anunzi.

---

## Crear una función de código

En la ficha del agente: **Funciones → + Agregar función → Código → Función de código**.

| Campo | Qué poner |
|---|---|
| **Nombre** | Sin espacios, por ejemplo `validarDocumento`. Es el nombre con el que el agente la llama. |
| **Descripción** | Cuándo debe usarla el agente. Es lo más importante: el agente decide con esto. |
| **Código JavaScript** | Tu código (ver abajo). |
| **Parámetros (esquema JSON)** | Qué datos le pasa el agente. |
| **Tiempo máximo** | Entre 1 y 60 segundos (30 por defecto). |

Guarda y **publica** la versión para que se use en las llamadas. Puedes probarla antes con **Probar en texto**, que usa el borrador.

### Parámetros

Se definen con un **esquema JSON**: un objeto con las propiedades que el agente tiene que completar y cuáles son obligatorias.

```json
{
  "type": "object",
  "properties": {
    "dni": { "type": "string", "description": "Número de documento, solo dígitos" },
    "tipo_documento": { "type": "string", "enum": ["DNI", "PASAPORTE"], "description": "Tipo de documento" }
  },
  "required": ["dni"]
}
```

Usa descripciones claras: el agente las lee para saber qué pedir y cómo pasarlo.

---

## Cómo escribir el código

Puedes escribirlo de dos maneras:

**1. Una función con el mismo nombre** (recomendado si traes código de Node). La llamamos con los parámetros:

```javascript
async function validarDocumento(params) {
  if (!/^\d{7,8}$/.test(params.dni)) return { ok: false, mensaje: "El DNI no es válido. Pedirlo de nuevo." };
  const r = await fetch("https://api.miempresa.com/pacientes?dni=" + params.dni);
  const datos = await r.json();
  return { ok: true, existe: datos.length > 0 };
}
```

**2. Código suelto que termina con `return`:**

```javascript
const total = params.cantidad * 1500;
return { total, mensaje: "El total es " + total + " pesos." };
```

### Qué tienes disponible

| Nombre | Qué es |
|---|---|
| `params` (o `args`) | Los parámetros que mandó el agente. |
| `dv` | Variables de la llamada, como texto: `call_id`, `direction`, `user_number` (teléfono de la persona), `agent_number`, `telefono` y las variables dinámicas que mandes al crear la llamada. |
| `metadata` | La metadata de la llamada. |
| `sesion` | Un objeto que **se conserva entre tus funciones durante la misma llamada**. Ver abajo. |
| `fetch` | Para llamar a cualquier API por HTTPS. |
| `require(...)` | Módulos de Node: `https`, `http`, `url`, `crypto`, `buffer`, `querystring`, `util`, `events`, `zlib` (también con `node:`, como `require("node:https")`). |
| `async` / `await`, `setTimeout`, `URL`, `Buffer`, `JSON`, `Date`, etc. | JavaScript moderno (Node). |

No hay acceso a archivos ni a otros módulos.

### Lo que devuelves

Devuelve un objeto (o texto). El agente lo recibe y lo usa para responder. Algunas recomendaciones:

* Incluye un campo `mensaje` con lo que el agente debe hacer o decir a continuación (por ejemplo, *"Documento válido. Pedir la fecha de nacimiento."*).
* No devuelvas datos que el agente no deba leerle a la persona. Si necesitas pasar un dato interno a la siguiente función, devuélvelo con un nombre claro (por ejemplo `_paci_codigo`) e indícalo en la descripción de la siguiente función, o guárdalo en `sesion`.
* Si algo falla, devuelve un objeto con el error explicado (`{ ok: false, mensaje: "..." }`). Si tu código lanza un error, el agente se entera de que la función falló.

---

## Código compartido

Si varias funciones usan lo mismo (la conexión a tu API, funciones auxiliares, constantes), escríbelo **una sola vez** en la sección **Código compartido de las funciones** de la ficha. Se agrega al principio de todas tus funciones de código.

```javascript
// Código compartido
const API = "https://api.miempresa.com";
const TOKEN = "tu-token-de-la-api";
async function api(ruta, cuerpo) {
  const r = await fetch(API + ruta, {
    method: "POST",
    headers: { "Content-Type": "application/json", "Authorization": "Bearer " + TOKEN },
    body: JSON.stringify(cuerpo),
  });
  if (!r.ok) throw new Error("La API respondió " + r.status);
  return r.json();
}
```

Y en cada función:

```javascript
async function reservarTurno(params) {
  const r = await api("/turnos/reservar", { turno: params.turno_codigo });
  return { ok: true, mensaje: "Turno reservado." };
}
```

---

## Datos que duran toda la llamada: `sesion`

`sesion` es un objeto que puedes leer y escribir en cualquier función, y **se conserva entre las funciones de la misma llamada**. Sirve, por ejemplo, para recordar que la persona ya se identificó o qué turnos ya se reservaron:

```javascript
async function validarPaciente(params) {
  // … validar …
  sesion.paciente = { codigo: 1234, verificado: true };
  return { ok: true, mensaje: "Identidad verificada." };
}

async function reservarTurno(params) {
  if (!sesion.paciente?.verificado) return { ok: false, mensaje: "Primero hay que verificar la identidad." };
  sesion.reservados = sesion.reservados || [];
  if (sesion.reservados.includes(params.turno_codigo)) return { ok: true, mensaje: "Ese turno ya se reservó en esta llamada." };
  // … reservar …
  sesion.reservados.push(params.turno_codigo);
  return { ok: true, mensaje: "Turno reservado." };
}
```

Se guarda como JSON entre una función y otra: usa objetos, listas, textos y números (no `Set`, `Map` ni funciones). Cuando termina la llamada, `sesion` se borra.

---

## Límites

| | |
|---|---|
| Tiempo máximo por ejecución | 1 a 60 segundos (30 por defecto) |
| Resultado que ve el agente | hasta 15.000 caracteres |
| Código compartido | hasta 100.000 caracteres |

---

## Credenciales y datos sensibles

* Tu código queda guardado en la configuración del agente y solo lo ven quienes pueden editar el agente.
* Para claves de tu API, lo más prolijo es ponerlas **una sola vez** en el código compartido, en lugar de repetirlas en cada función.
* Nunca pongas credenciales en el prompt ni en las descripciones: esos textos los lee el modelo.

---

## Si venías del motor anterior

En el motor anterior las funciones de código **no recibían parámetros** del agente y no podían usar módulos de Node (`require`). En VPower sí: el mismo código que pruebas en tu computadora con Node funciona, y el agente le pasa los datos que necesita.

Al pasar tu agente a VPower, las funciones de código se copian tal cual. Revisa el **esquema de parámetros** de cada una.
