> ## Documentation Index
> Fetch the complete documentation index at: https://docs.plazbot.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Agente de IA

> Guía completa sobre la configuración del agente de IA en Plazbot

### Configuracion del Agente de IA

Este documento describe la estructura y configuracion del Agente de IA en Plazbot. Un agente puede estar vinculado a un portal web, widget o canal de mensajeria como WhatsApp o cualquier software que tengas.

<Card title="GitHub - Ejemplos" icon="github" href="https://github.com/plazbot/plazbot-sdk-examples">
  Repositorio con ejemplos funcionales para crear tus agentes.
</Card>

### Inicializacion

Puedes usar la clase unificada `Plazbot` o importar `Agent` de forma individual:

<CodeGroup>
  ```ts Plazbot (recomendado) theme={null}
  import { Plazbot } from 'plazbot';

  const plazbot = new Plazbot({
    workspaceId: "YOUR_WORKSPACE_ID",
    apiKey: "YOUR_API_KEY",
    zone: "LA" // "EU" para Europa
  });

  // Usar: plazbot.agent.addAgent(...)
  ```

  ```ts Agent individual theme={null}
  import { Agent } from 'plazbot';

  const bot = new Agent({
    workspaceId: "YOUR_WORKSPACE_ID",
    apiKey: "YOUR_API_KEY",
    zone: "LA"
  });

  // Usar: bot.addAgent(...)
  ```
</CodeGroup>

### Creacion del Agente

El agente es la unidad base del SDK. Puedes crear agentes con caracteristicas especificas y desplegarlos en diferentes canales: Portal de IA, Widget, WhatsApp o cualquier herramienta empresarial.

```ts theme={null}
const agent = await plazbot.agent.addAgent(config);
const agentId = agent.agentId;
```

### Actualizar Agente

```ts theme={null}
await plazbot.agent.updateAgent(agentId, {
  name: "Agente Actualizado",
  buffer: 8
});
```

Para trabajar con los agentes, existe un archivo JSON que funciona como el configurador inicial. No es necesario completar todos los campos, configura solo lo que necesites.

<Tip>
  Proporcionamos archivos de configuracion basico y avanzado en el [**Repositorio de GitHub**](https://github.com/plazbot/plazbot-sdk-examples).
</Tip>

### Estructura del Archivo `agent.config.json`

```json theme={null}
{
  "name": "Sales Clinic",
  "description": "Virtual Agent IA assistant of the Dental Clinic Smiles",
  "prompt": "You are Máximo, a professional virtual assistant for Smiles Dental Clinic. Help patients with appointments, general information, and guide them through our services. Always maintain a professional yet friendly tone.",
  "zone": "LA",
  "buffer": 15,
  "color": "blue",
  "question": "How can I help you today?",
  "timezone": "America/Lima",
  "enable": true,
  "tags": [
    "health",
    "dentistry",
    "ia",
    "plazbot"
  ],
  "showInChat": false,
  "useToolCalling": true,
  "responseMode": "direct",
  "batchWaitSeconds": 3,
  "version": "v2.0",
  "enableWidget": true,
  "darkWidget": true,
  "nameWidget": "Dental Assistant",
  "initialShowWidget": true,
  "examples": [
    { "value": "How to schedule an appointment?", "color": "green" },
    { "value": "What are your office hours?", "color": "blue" },
    { "value": "Do you accept insurance?", "color": "orange" },
    { "value": "Emergency contact information", "color": "gray" },
    { "value": "Location and directions", "color": "white" }
  ],
  "instructions": {
    "tone": "professional",
    "style": "short answers",
    "personality": "friendly",
    "objective": "help with clarity",
    "language": "es-419",
    "emojis": false,
    "preferredFormat": "plain text",
    "maxWords": 80,
    "avoidTopics": [
      "laboratory costs",
      "external claims",
      "specific medical diagnoses"
    ],
    "respondOnlyIfKnows": true,
    "maintainToneBetweenMessages": true,
    "greeting": "Hello, I am Máximo, your virtual assistant from Smiles Dental Clinic. How can I help you today?"
  },
  "person": {
    "name": "Máximo",
    "role": "Virtual customer service assistant",
    "speaksInFirstPerson": true,
    "isHuman": false
  },
  "fallbacks": {
    "noAnswer": "Sorry, I don't have information on that topic. Let me connect you with one of our specialists.",
    "serviceError": "There was a problem processing your request. Please try again later or contact us directly.",
    "doNotUnderstand": "Could you please repeat it in another way? I want to make sure I help you correctly."
  },
  "rules": {
    "doNotMentionPrices": false,
    "doNotDiagnose": true,
    "doNotRespondOutsideHours": "Our office hours are Monday to Saturday, from 8am to 6pm. For emergencies, please call our emergency line."
  },
  "customAIConfig": true,
  "aiProviders": [
    {
      "provider": "openai",
      "model": "gpt-4o",
      "apiToken": "sk-proj-xxxxxxxxxxxxx",
      "temperature": 0.7,
      "maxTokens": 4096,
      "isDefault": true
    },
    {
      "provider": "claude",
      "model": "claude-3-5-sonnet-20241022",
      "apiToken": "sk-ant-xxxxxxxxxxxxx",
      "temperature": 0.5,
      "maxTokens": 8192,
      "isDefault": false
    }
  ],
  "channels": [
    {
      "channel": "whatsapp",
      "key": "+51987654321",
      "multianswer": false
    },
    {
      "channel": "telegram",
      "key": "smiles_clinic_bot",
      "multianswer": true
    }
  ],
  "services": [
    {
      "intent": "schedule_appointment",
      "reference": "Service for scheduling patient appointments at the dental clinic",
      "enabled": true,
      "method": "POST",
      "tags": ["appointment", "scheduling"],
      "endpoint": "https://api.smilesclinic.com/v1/appointments/schedule",
      "requiredFields": [
        {
          "name": "patient_name",
          "description": "Full name of the patient who wants to schedule the appointment",
          "promptHint": "Could you please provide your full name?",
          "type": "string"
        },
        {
          "name": "email",
          "description": "Patient's email address for appointment confirmation",
          "promptHint": "What's your email address for the appointment confirmation?",
          "type": "email"
        },
        {
          "name": "phone",
          "description": "Patient's phone number for contact",
          "promptHint": "Could you provide your phone number?",
          "type": "phone"
        },
        {
          "name": "preferred_date",
          "description": "Preferred date and time for the appointment",
          "promptHint": "What date and time would work best for your appointment?",
          "type": "datetime"
        },
        {
          "name": "service_type",
          "description": "Type of dental service needed",
          "promptHint": "What type of dental service do you need? (cleaning, consultation, etc.)",
          "type": "string"
        }
      ],
      "headers": {
        "Authorization": "Bearer {{clinic_api_key}}",
        "Content-Type": "application/json",
        "X-Clinic-ID": "smiles_001"
      },
      "bodyTemplate": {
        "patient": {
          "name": "{{patient_name}}",
          "email": "{{email}}",
          "phone": "{{phone}}"
        },
        "appointment": {
          "datetime": "{{preferred_date|format('yyyy-MM-dd HH:mm')}}",
          "service": "{{service_type}}",
          "timezone": "America/Lima"
        }
      },
      "bodySchema": {
        "patient_name": "string",
        "email": "string",
        "preferred_date": "date",
        "service_type": "string"
      },
      "responseMapping": {
        "confirmation_id": "$.data.appointment.id",
        "scheduled_date": "$.data.appointment.datetime",
        "status": "$.status",
        "doctor_name": "$.data.appointment.doctor.name",
        "conflict_reason": "$.error.reason"
      },
      "responseMessage": "Your appointment has been successfully scheduled for {{scheduled_date}} with Dr. {{doctor_name}}",
      "responseConditions": [
        {
          "condition": "$.status == 'confirmed'",
          "message": "¡Perfect! Your appointment has been confirmed for {{scheduled_date}} with Dr. {{doctor_name}}. We'll send you a reminder 24 hours before. Confirmation ID: {{confirmation_id}}",
          "nextService": "send_appointment_reminder"
        },
        {
          "condition": "$.status == 'conflict'",
          "message": "Sorry, that time slot is not available. {{conflict_reason}}. Would you like me to suggest other available times?",
          "nextService": "suggest_alternative_times"
        },
        {
          "condition": "$.status == 'error' && $.error.code == 'invalid_email'",
          "message": "The email address provided seems invalid. Could you please verify your email address?",
          "nextService": "verify_contact_info"
        },
        {
          "condition": "$.status == 'error' && $.error.code == 'past_date'",
          "message": "I cannot schedule appointments for past dates. Could you please choose a future date?"
        },
        {
          "condition": "$.status == 'pending'",
          "message": "Your appointment request is being reviewed. We'll contact you within 24 hours to confirm availability and finalize the details."
        }
      ],
      "action": "conversar_humano"
    },
    {
      "intent": "check_insurance",
      "reference": "Service to verify patient insurance coverage and benefits",
      "enabled": true,
      "method": "GET",
      "tags": ["insurance", "verification"],
      "endpoint": "https://api.smilesclinic.com/v1/insurance/verify",
      "requiredFields": [
        {
          "name": "insurance_provider",
          "description": "Name of the insurance company",
          "promptHint": "What's your insurance provider name?",
          "type": "string"
        },
        {
          "name": "policy_number",
          "description": "Insurance policy or member ID number",
          "promptHint": "Could you provide your policy or member ID number?",
          "type": "string"
        }
      ],
      "headers": {
        "Authorization": "Bearer {{insurance_api_key}}",
        "Content-Type": "application/json"
      },
      "responseMapping": {
        "coverage_status": "$.data.coverage.status",
        "deductible": "$.data.coverage.deductible",
        "copay": "$.data.coverage.copay",
        "covered_services": "$.data.coverage.services"
      },
      "responseMessage": "Your insurance verification is complete. Coverage status: {{coverage_status}}",
      "responseConditions": [
        {
          "condition": "$.data.coverage.status == 'active'",
          "message": "Great news! Your insurance is active. Your copay is ${{copay}} and your remaining deductible is ${{deductible}}. Covered services include: {{covered_services}}."
        },
        {
          "condition": "$.data.coverage.status == 'inactive'",
          "message": "It appears your insurance policy is not currently active. Please contact your insurance provider or we can discuss our self-pay options."
        },
        {
          "condition": "$.data.coverage.status == 'not_found'",
          "message": "I couldn't find your policy in our system. Please verify your insurance information or contact us directly for assistance."
        }
      ]
    }
  ],

  "actions": [
    {
      "intent": "assign_urgent_tag",
      "reference": "Tags patients as urgent when they mention emergency dental situations",
      "tags": ["emergency", "urgent"],
      "enabled": true,
      "responseMessage": "I've marked your case as urgent and notified our emergency team.",
      "responseJson": false,
      "responseExact": true,
      "action": [
        {
          "type": "action.tag",
          "value": "urgent_case"
        },
        {
          "type": "action.asign",
          "value": "emergency@smilesclinic.com"
        }
      ]
    },
    {
      "intent": "schedule_follow_up",
      "reference": "Automatically schedules follow-up appointments and assigns appropriate case management",
      "tags": ["follow-up", "scheduling"],
      "enabled": true,
      "responseMessage": "Your follow-up has been scheduled and assigned to our treatment coordinator.",
      "responseJson": false,
      "responseExact": false,
      "action": [
        {
          "type": "action.stage",
          "value": "follow_up_scheduled"
        },
        {
          "type": "action.segmentation",
          "value": "post_treatment_care"
        }
      ]
    },
    {
      "intent": "end_consultation",
      "reference": "Ends the AI consultation when the patient no longer needs assistance",
      "tags": ["consultation", "end"],
      "enabled": true,
      "responseMessage": "Thank you for contacting Smiles Dental Clinic. Have a great day!",
      "responseJson": false,
      "responseExact": true,
      "action": [
        {
          "type": "action.agentShutDown",
          "value": "true"
        },
        {
          "type": "action.solved",
          "value": "true"
        }
      ]
    }
  ]
}
```

### Canales (`channels`)

Los canales definen dónde y cómo tu agente puede comunicarse con los usuarios.

| Campo     | Tipo   | Requerido | Descripción                                                 |
| --------- | ------ | --------- | ----------------------------------------------------------- |
| `channel` | string | ✅ Sí      | Tipo de canal: `whatsapp`, `telegram`, `messenger`, etc.    |
| `key`     | string | ✅ Sí      | Identificador del canal (número de teléfono para WhatsApp). |

#### Ejemplo de Canales

```json theme={null}
"channels": [
  { "channel": "whatsapp", "key": "123456789" },
  { "channel": "telegram", "key": "@mi_bot" },
  { "channel": "messenger", "key": "page_id_123" }
]
```

### Campos principales del agente

| Campo            | Descripción                                                                                                             |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------- |
| **name**         | Nombre del agente. Visible en el panel. `Requerido`                                                                     |
| **prompt**       | Instrucciones base para el comportamiento del agente. `Requerido`                                                       |
| **buffer**       | Cantidad de mensajes que se mantienen como contexto. Rango: 3 a 20. `Requerido`                                         |
| color            | Color de presentación. Valores: `blue`, `orange`, `gray`, `green`, `white`.                                             |
| question         | Pregunta principal que se muestra en el portal.                                                                         |
| description      | Descripción general del agente.                                                                                         |
| **zone**         | Zona donde opera el agente: `LA` (Latinoamérica) o `EU` (Europa). `Requerido`                                           |
| timezone         | Zona horaria. Ejemplo: `America/Lima`. [TimeZone Formats](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) |
| tags             | Etiquetas internas para clasificar agentes.                                                                             |
| examples         | Preguntas sugeridas. Hasta 5.                                                                                           |
| showInChat       | Si el agente se muestra en el widget/chat. (boolean)                                                                    |
| enable           | Si el agente esta habilitado o no. (boolean)                                                                            |
| version          | Version del agente (auto-incrementado). Formato: `v2.0`, `v2.1`, etc.                                                   |
| useToolCalling   | Si usa el orquestador de Tool Calling (`true`) o el clasico (`false`). Default: `true`.                                 |
| responseMode     | Modo de respuesta: `direct` (inmediato) o `batched` (espera mensajes consecutivos). Default: `direct`.                  |
| batchWaitSeconds | Segundos de espera para acumular mensajes consecutivos (solo si `responseMode=batched`). Rango: 2-10. Default: 3.       |
| customAIConfig   | Habilita configuracion personalizada de proveedores de IA. (boolean)                                                    |
| aiProviders      | Array de proveedores de IA configurados. Ver seccion "Modelo IA".                                                       |

### Instrucciones (`instructions`)

| Campo                       | Tipo    | Descripción                                            |
| --------------------------- | ------- | ------------------------------------------------------ |
| tone                        | string  | Tono de comunicación: `professional`, `friendly`, etc. |
| style                       | string  | Estilo de respuestas: `short answers`, `detailed`.     |
| personality                 | string  | Personalidad del agente.                               |
| objective                   | string  | Objetivo principal del agente.                         |
| language                    | string  | Idioma en que debe responder. Ver tabla de idiomas.    |
| emojis                      | boolean | Si puede usar emojis.                                  |
| preferredFormat             | string  | `plain text` o `markdown`.                             |
| maxWords                    | number  | Máximo de palabras por respuesta.                      |
| avoidTopics                 | array   | Lista de temas prohibidos.                             |
| respondOnlyIfKnows          | boolean | Si debe evitar responder sin información confiable.    |
| maintainToneBetweenMessages | boolean | Mantiene el mismo tono entre mensajes.                 |
| greeting                    | string  | Mensaje de bienvenida.                                 |

**Opciones Objetive**
"help with clarity"	Enfocado en brindar respuestas claras
"sell more"	Promociona productos o servicios
"support users"	Ayuda a resolver problemas
"guide actions"	Brinda pasos concretos o instrucciones

**Opciones Personalidad**
"friendly"	Agradable y empático
"serious"	Reservado y directo
"funny"	Con toques de humor sutil
"robotic"	Más neutral, tipo IA técnica

**Opciones preferredFormat**
"plain text"	Texto simple
"markdown"	Permite negritas, listas, enlaces
"html"	Usado si se integrará en un entorno web

**Opciones Style**
"short answers"	Respuestas breves y directas
"detailed"	Respuestas explicativas, útiles para asistencia técnica
"bullet points"	Instrucciones u opciones en lista (ideal para pasos o listas)
"conversational"	Estilo fluido y natural, más humano

**Opciones Tono**
"professional"	Tono formal, educado, propio para empresas
"friendly"	Tono amigable, cercano, ideal para atención al cliente
"casual"	Informal, con lenguaje relajado y natural
"neutral"	Objetivo, sin inclinación emocional

### Persona del Agente (`person`)

| Campo               | Tipo    | Descripción                  |
| ------------------- | ------- | ---------------------------- |
| name                | string  | Nombre que usará el agente.  |
| role                | string  | Rol representado.            |
| speaksInFirstPerson | boolean | Habla en primera persona.    |
| isHuman             | boolean | Simula ser una persona real. |

### Reglas y Fallbacks

### Fallbacks

| Campo           | Tipo   | Descripción                         |
| --------------- | ------ | ----------------------------------- |
| noAnswer        | string | Mensaje si no tiene respuesta.      |
| serviceError    | string | Mensaje de error de servicio.       |
| doNotUnderstand | string | Mensaje si no entiende la consulta. |

### Reglas

| Campo                    | Tipo    | Descripción                                                                |
| ------------------------ | ------- | -------------------------------------------------------------------------- |
| doNotMentionPrices       | boolean | No hablar de precios.                                                      |
| doNotDiagnose            | boolean | No hacer diagnósticos médicos.                                             |
| doNotRespondOutsideHours | string  | Mensaje fuera del horario definido. Trabaja junto con el campo de Timezone |

### Configuración de Modelo IA

Plazbot te permite configurar proveedores de IA personalizados para cada agente. Por defecto, los agentes usan el token de OpenAI configurado en tu workspace, pero puedes habilitar configuración personalizada para usar diferentes proveedores (OpenAI, Claude, Gemini) con sus propios tokens y parámetros.

#### Habilitar Configuración Personalizada

```json theme={null}
{
  "customAIConfig": true,
  "aiProviders": [
    {
      "provider": "openai",
      "model": "gpt-4o",
      "apiToken": "sk-proj-xxxxxxxxxxxxx",
      "temperature": 0.7,
      "maxTokens": 4096,
      "isDefault": true
    },
    {
      "provider": "claude",
      "model": "claude-3-5-sonnet-20241022",
      "apiToken": "sk-ant-xxxxxxxxxxxxx",
      "temperature": 0.5,
      "maxTokens": 8192,
      "isDefault": false
    }
  ]
}
```

#### Campos de `aiProviders`

| Campo       | Tipo    | Requerido | Descripción                                              |
| ----------- | ------- | --------- | -------------------------------------------------------- |
| provider    | string  | ✅ Sí      | Proveedor de IA: `openai`, `claude`, o `gemini`          |
| model       | string  | ✅ Sí      | Modelo específico a usar. Ver modelos disponibles abajo. |
| apiToken    | string  | ✅ Sí      | Token de API del proveedor.                              |
| temperature | number  | ❌ No      | Controla creatividad (0-2). Default: 0.7                 |
| maxTokens   | number  | ❌ No      | Longitud máxima de respuesta. Recomendado: 4096          |
| isDefault   | boolean | ❌ No      | Define cuál proveedor usar por defecto.                  |

#### Modelos Disponibles por Proveedor

**OpenAI:**

* `gpt-5.1`
* `gpt-5.1-codex`
* `gpt-5`
* `gpt-4o` (recomendado)
* `gpt-4o-mini`
* `gpt-4-turbo`
* `o1-preview`
* `o1-mini`

**Claude (Anthropic):**

* `claude-3-5-sonnet-20241022` (recomendado)
* `claude-3-5-sonnet-20240620`
* `claude-3-opus-20240229`
* `claude-3-sonnet-20240229`
* `claude-3-haiku-20240307`

**Gemini (Google):**

* `gemini-2.0-flash-exp` (recomendado)
* `gemini-1.5-pro`
* `gemini-1.5-flash`
* `gemini-1.5-flash-8b`

#### Parámetros de Temperature

| Valor     | Descripción                               | Uso Recomendado                   |
| --------- | ----------------------------------------- | --------------------------------- |
| 0 - 0.3   | Respuestas muy predecibles y consistentes | Soporte técnico, datos precisos   |
| 0.5 - 0.7 | Balance entre creatividad y precisión     | Uso general (recomendado)         |
| 1.0 - 1.5 | Respuestas más creativas y variadas       | Marketing, contenido creativo     |
| 1.5 - 2.0 | Muy creativo e impredecible               | Escritura creativa, brainstorming |

#### Parámetros de MaxTokens

| Valor | Descripción                     | Uso Recomendado                      |
| ----- | ------------------------------- | ------------------------------------ |
| 1024  | Respuestas cortas               | Respuestas breves, preguntas simples |
| 2048  | Respuestas medianas             | Explicaciones moderadas              |
| 4096  | Respuestas largas (recomendado) | Uso general                          |
| 8192  | Respuestas muy largas           | Análisis detallados                  |
| 16384 | Respuestas extensas             | Documentos completos                 |

<Warning>
  **Importante:** Si activas `customAIConfig: true`, debes agregar al menos un proveedor en el array `aiProviders`. Si el array está vacío, el sistema usará la configuración por defecto del workspace.
</Warning>

<Tip>
  **Tip:** Puedes configurar múltiples proveedores y el agente usará el que tenga `isDefault: true`. Esto es útil para A/B testing o para tener proveedores de respaldo.
</Tip>

### Códigos de Idioma

| Valor  | Descripción                     |
| ------ | ------------------------------- |
| es     | Español general                 |
| es-419 | Español latinoamericano neutral |
| es-ES  | Español de España               |
| en     | Inglés general                  |
| en-US  | Inglés estadounidense           |
| en-GB  | Inglés británico                |
| fr     | Francés general                 |
| fr-FR  | Francés de Francia              |
| pt-BR  | Portugués brasileño             |
| de     | Alemán                          |

### **Enviar mensaje al Agente de IA**

```ts theme={null}
const response = await bot.onMessage({
  agentId: "agentId",
  question: "Can you give me a summary of the new Meta WhatsApp prices?",
  sessionId: "2aff0c11-434f-4d7c-a325-697128bb8a20",
  file: "https://.../archivo.pdf", // 
  multipleAnswers: true // Optional
});

console.log("💬 IA Response:", respuesta);
```

| Campo             | Tipo      | Requerido | Descripción                                                                                                                                         |
| ----------------- | --------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `agentId`         | `string`  | ✅ Sí      | Identificador único del agente. Se utiliza para recuperar su configuración y conocimiento.                                                          |
| `question`        | `string`  | ✅ Sí      | Pregunta o mensaje del usuario que la IA debe responder.                                                                                            |
| `sessionId`       | `string`  | ✅ Sí      | Identificador de sesión único para mantener el contexto y el historial (buffer) de la conversación.                                                 |
| `file`            | `string`  | ❌ No      | URL pública opcional de una imagen o archivo PDF. El contenido será extraído y usado si es relevante para la respuesta.                             |
| `multipleAnswers` | `boolean` | ❌ No      | Si se establece en `true`, la respuesta será devuelta en múltiples bloques (array) en lugar de un único texto. Ideal para respuestas estructuradas. |

### Tipos de Archivos Soportados en `onMessage` (OCR)

| Tipo de Archivo                         | Soportado | Notas                                                                      |
| --------------------------------------- | --------- | -------------------------------------------------------------------------- |
| `.jpg`, `.png`, `.bmp`, `.gif`, `.tiff` | ✅ Sí      | Formatos estándar de imagen                                                |
| `.pdf`                                  | ✅ Sí      | Solo si el PDF contiene **texto incrustado** o es una **imagen escaneada** |
| `.docx`, `.xlsx`                        | ❌ No      | No se admite para procesamiento OCR                                        |
| `.txt`, `.json`, etc.                   | ❌ No      | No relevantes para extracción OCR                                          |

Respuesta esperada:

```json theme={null}
{
  "answer": "Los precios de Meta WhatsApp se actualizaron...",
  "sources": [
    {
      "title": "Documento de precios",
      "content": "Fragmento relevante del documento..."
    }
  ],
  "actionsExecuted": [
    {
      "name": "action.tag",
      "intent": "consulta_precios",
      "result": {}
    }
  ]
}
```

| Campo             | Tipo   | Descripcion                                                                                      |
| ----------------- | ------ | ------------------------------------------------------------------------------------------------ |
| `answer`          | string | Respuesta del agente en texto. Si `multipleAnswers = true`, se devuelve como array en `answers`. |
| `sources`         | array  | Fuentes del knowledge base usadas para generar la respuesta (si aplica).                         |
| `actionsExecuted` | array  | Acciones que se ejecutaron durante la respuesta (si aplica).                                     |

### Streaming SSE (Server-Sent Events)

Los endpoints `/on-message` y `/on-message-portal` soportan streaming SSE. Cuando envias `stream: true`, la respuesta se emite como `text/event-stream` con chunks progresivos en vez de esperar la respuesta completa.

<Warning>
  **Requisito:** El agente debe tener `useToolCalling: true` para que el streaming funcione. Si `useToolCalling` es `false`, el endpoint retorna JSON normal aunque envies `stream: true`.
</Warning>

<Note>
  **Portal y Widget:** Los agentes asociados a Portales de IA y Widgets siempre deben tener `useToolCalling: true` activado para una experiencia optima con streaming.
</Note>

#### Request con Stream

```ts theme={null}
const response = await fetch('https://api.plazbot.com/api/agent/on-message', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_API_KEY',
    'x-workspace-id': 'YOUR_WORKSPACE_ID'
  },
  body: JSON.stringify({
    agentId: "agentId",
    question: "Cuales son los horarios?",
    sessionId: "2aff0c11-434f-4d7c-a325-697128bb8a20",
    stream: true
  })
});
```

#### Formato de Chunks SSE

Cada linea sigue el formato `data: {json}\n\n`. Los tipos de chunks son:

| Tipo          | Descripcion                                     | Campos                                            |
| ------------- | ----------------------------------------------- | ------------------------------------------------- |
| `text`        | Token parcial de texto                          | `content`: texto parcial                          |
| `tool_call`   | El agente ejecuta una herramienta (API, accion) | `tool_name`: nombre de la herramienta             |
| `tool_result` | Resultado de la herramienta ejecutada           | `tool_name`, `tool_result`                        |
| `done`        | Stream finalizado                               | `input_tokens`, `output_tokens`, `estimated_cost` |
| `error`       | Error durante el procesamiento                  | `error`: mensaje de error                         |

#### Ejemplo de Chunks

```
data: {"type":"tool_call","tool_name":"search_knowledge_base"}

data: {"type":"tool_result","tool_name":"search_knowledge_base"}

data: {"type":"text","content":"Los"}

data: {"type":"text","content":" horarios"}

data: {"type":"text","content":" de atencion son..."}

data: {"type":"done","input_tokens":1250,"output_tokens":380,"estimated_cost":0.0045}
```

#### Consumir el Stream (JavaScript/TypeScript)

```ts theme={null}
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
let fullText = '';

while (true) {
  const { done, value } = await reader.read();
  if (done) break;

  buffer += decoder.decode(value, { stream: true });
  const lines = buffer.split('\n');
  buffer = lines.pop() || '';

  for (const line of lines) {
    if (!line.startsWith('data: ')) continue;
    const chunk = JSON.parse(line.substring(6));

    if (chunk.type === 'text') {
      fullText += chunk.content;
      // Actualizar la UI progresivamente
    } else if (chunk.type === 'tool_call') {
      // Mostrar indicador: "Buscando informacion..."
    } else if (chunk.type === 'done') {
      // Stream finalizado
      console.log('Tokens:', chunk.input_tokens, chunk.output_tokens);
    }
  }
}
```

#### Proveedores Soportados

| Proveedor          | Streaming | Notas                           |
| ------------------ | --------- | ------------------------------- |
| OpenAI             | Soportado | Tokens emitidos uno a uno       |
| Claude (Anthropic) | Soportado | Chunks mas grandes que OpenAI   |
| Gemini (Google)    | Soportado | Tokens emitidos progresivamente |

#### Retrocompatibilidad

El parametro `stream` es opcional con default `false`. Los clientes existentes que no envien `stream` continuan recibiendo la respuesta JSON completa sin ningun cambio.

### Listar Agentes

Devuelve todos los agentes dentro del workspace.

```ts theme={null}
const agents = await plazbot.agent.getAgents();
```

### Obtener Agente por ID

```ts theme={null}
const agent = await plazbot.agent.getAgentById({ id: agentId });
```

### Copiar Agente

Crea una copia exacta del agente.

```ts theme={null}
const copy = await plazbot.agent.copyAgent({ id: agentId });
```

### Obtener Agente por Canal

Busca un agente por su canal y clave asociada.

```ts theme={null}
const agent = await plazbot.agent.getAgentByChannel({
  channel: "whatsapp",
  key: "+51987654321"
});
```

### Eliminar Agente

Elimina un agente y remueve su referencia de cualquier portal asociado.

```ts theme={null}
await plazbot.agent.deleteAgent({ id: agentId });
```

***

### Configuracion Rapida (Quick Config)

Actualiza secciones especificas del agente sin enviar toda la configuracion:

```ts theme={null}
// Instrucciones
await plazbot.agent.setInstructions(agentId, {
  tone: "professional",
  style: "short answers",
  language: "es-419",
  emojis: false,
  maxWords: 100
});

// Persona
await plazbot.agent.setPersona(agentId, {
  name: "Maximo",
  role: "Asistente virtual",
  speaksInFirstPerson: true,
  isHuman: false
});

// Fallbacks
await plazbot.agent.setFallbacks(agentId, {
  noAnswer: "No tengo informacion sobre ese tema.",
  serviceError: "Hubo un problema. Intenta mas tarde.",
  doNotUnderstand: "Podrias reformular tu pregunta?"
});

// Reglas
await plazbot.agent.setRules(agentId, {
  doNotMentionPrices: false,
  doNotDiagnose: true,
  doNotRespondOutsideHours: "Lunes a Viernes 9am a 6pm."
});

// Tags
await plazbot.agent.setTags(agentId, ["ventas", "soporte"]);

// Greeting (saludo)
await plazbot.agent.setGreeting(agentId, "Hola! Soy tu asistente virtual.");
```

***

### Debug Logs

Obtener los logs de debug del agente para diagnosticar problemas:

```ts theme={null}
const logs = await plazbot.agent.getDebugLogs(agentId);
console.log(logs);
```

***

### Utilidades de IA

Mejora un prompt usando inteligencia artificial:

```ts theme={null}
const result = await plazbot.agent.improvePrompt("eres un bot que ayuda personas");
console.log(result.result); // Prompt mejorado
```

***

### Manejo de Errores

```ts theme={null}
try {
  const response = await plazbot.agent.onMessage({
    agentId: "agent_123",
    question: "Cuales son los horarios?",
    sessionId: "session_456"
  });
} catch (error) {
  if (error.status === 401) {
    // Error de autenticacion - Revisa tu API Key
  } else if (error.status === 404) {
    // Agente no encontrado
  } else if (error.status === 429) {
    // Rate limit - Espera antes de reintentar
  }
}
```

<Tip>
  Usa `multipleAnswers: true` en `onMessage` cuando necesites respuestas estructuradas para integraciones complejas.
</Tip>

<Card title="Necesitas Ayuda?" icon="life-ring">
  Contacta a nuestro equipo en [support@plazbot.com](mailto:support@plazbot.com) o revisa los ejemplos en el [repositorio de GitHub](https://github.com/plazbot/plazbot-sdk-examples).
</Card>
