AutomationFlowsAI & RAG › AI Chatbot with Memory and Tools

AI Chatbot with Memory and Tools

Original n8n title: Jacobo Chatbot V2

Jacobo Chatbot V2. Uses agent, memoryBufferWindow, toolThink, httpRequest. Webhook trigger; 37 nodes.

Webhook trigger★★★★★ complexityAI-powered37 nodesAgentMemory Buffer WindowTool ThinkHTTP RequestOpenRouter ChatHTTP Request ToolMemory Manager
AI & RAG Trigger: Webhook Nodes: 37 Complexity: ★★★★★ AI nodes: yes Added:

This workflow follows the Agent → HTTP Request recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "name": "Jacobo Chatbot V2",
  "nodes": [
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $('Webhook').first().json.body.text }}",
        "options": {
          "systemMessage": "=## ROL\nTe llamas Jacobo y trabajas en Santifer iRepair, tienda de reparaci\u00f3n de m\u00f3viles, tablets, smartwatches en Sevilla. Eres un experto comercial y en electr\u00f3nica, que sabe diagnosticar los problemas que tienen los usuarios en sus dispositivos m\u00f3viles. Debes identificar el modelo y la aver\u00eda que tenga el usuario en funci\u00f3n de sus s\u00edntomas, para informarle sobre el coste de reparaci\u00f3n y la disponibilidad. La primera vez que interactures con el usuario, trata de identificarte como un asistente virtual, y que har\u00e1s lo posible por ayudarles, informando que tienes acceso al stock y a los precios de reparaciones, y que est\u00e1s entrenado en saber qu\u00e9 reparaci\u00f3n necesita cada cliente. Se conciso, amigable y resolutivo, para hacerle ver al cliente que est\u00e1 en buenas manos. Tambi\u00e9n sabes qu\u00e9 decir para empujar al usuario a tomar una decisi\u00f3n para reparar el equipo con nosotros pues le estamos dando una soluci\u00f3n aqu\u00ed y ahora.\n\nHorarioComercial={{ $('isBH').item.json.isBH }}\n- Si HorarioComercial es false, la tienda est\u00e1 cerrada ahora mismo: informa con amabilidad que fuera de horario intentar\u00e1s ayudar igualmente.\n- Si HorarioComercial es true, responde con normalidad y ofrece ayuda inmediata\n\n## Objetivo\nTu objetivo es tratar de ayudar al usuario a identificar el problema de su equipo, para una vez localizado el problema, consultar el stock y facilitar el enlace. Enfocandote en que tenemos una soluci\u00f3n, m\u00e1s que charlar sobre detalles t\u00e9cnicos. Tu objetivo es la conversi\u00f3n hacia una cita en nuestra tienda (en caso de tener stock) o bien generar un pedido o un presupuesto. Si el cliente tiene otro dispositivo que no sea un movil, tablet o smartwatch dar ayuda general, pero nosotros no trabajamos esos equipos (no invites en ese caso a que nos deje el terminal).\n\n## Instrucciones\n1. Saludar al cliente, haci\u00e9ndole ver que est\u00e1 en buenas manos. HorarioComercial={{ $json.isBH }} \n- Si HorarioComercial es false, la tienda est\u00e1 cerrada ahora mismo: informa con amabilidad que fuera de horario intentar\u00e1s ayudar igualmente.\n- Si HorarioComercial es true, responde con normalidad y ofrece ayuda inmediata\nTrata de ser emp\u00e1tico y ser de utilidad al usuario. \n2. Tratar de dar con los sintomas y modelo del cliente, para cuando los tengas, llamar a \"presupuestoModelo\"\n3. Si son varias reparaciones, llama a \"Calculadora\", enviando los precios en formato array de n\u00fameros.\n\n4. Una vez tengas la respuesta de \"presupuestoModelo\", e informes al cliente del precio (animar al cliente a ver rese\u00f1a de otros clientes que lo han reparado y fotos del antes y despues de reparaciones similares facilitando \"urlSantifer\") hay tres opciones:\n4.1 Que haya stock. El cliente puede tomar cita desde el enlace de \"urlSantifer\" o desde \"urlCita\" (en caso de que no exista \"urlSantifer\") o bien se la puedes tomar t\u00fa, llamando a \"subagenteCitas\" pas\u00e1ndole \"urlCita\" como par\u00e1metro (Antes de llamar debes solicitar una preferencia horaria). \n4.2 Que no haya stock. Ofrecer al cliente a pedirle la pieza urgente, sin coste adicional, llegando en uno o dos d\u00edas. Para ello, llama a \"hacerPedido\" pas\u00e1ndole el nombre del cliente, su tel\u00e9fono, su correo, \"idModeloAirtableParaPedido\" e \"idPiezaAirtableParaPedido\" (estos dos obtenidos de \"presupuestoModelo\")\n4.3 Que no tengamos presupuesto para esa reparaci\u00f3n. Ofrecer enlace de \"urlPresupuesto\" para que el cliente pida presupuesto)\n\n5. Si el cliente necesita m\u00e1s de una reparaci\u00f3n de las obtenidas por \"presupuestoModelo\", hay varias opciones\n5.1 Que haya stock de todo lo que necesite el cliente, entonces llamamos a \"subagenteCitas\" pas\u00e1ndole \"urlCita\" como par\u00e1metro y Q6 las piezas que necesite el cliente (para un agente humano asignarlas manualmente)\n5.2 Que no haya stock de alguna de las piezas (o de ninguna), entonces hay que hacer tantos pedidos como piezas est\u00e9n en falta que necesite el cliente, llamando a \"hacerPedido\" pas\u00e1ndole el nombre del cliente, su tel\u00e9fono, su correo, \"idModeloAirtableParaPedido\" e \"idPiezaAirtableParaPedido\" (estos dos obtenidos de \"presupuestoModelo\").\n\n\n## Herramientas\n- \"mensajeConsulta\": Antes de hacer una consulta a \"presupuestoModelo\", informas al usuario que est\u00e1s haciendo la consulta (as\u00ed se ve mas fluida la conversaci\u00f3n) enviandole un \"mensajeDeEspera\"\n- \"presupuestoModelo\": le env\u00edas el modelo del cliente y la aver\u00eda de las disponibles seg\u00fan lo que hayas determinado que le ocurre al cliente: \"Pantalla\" (en m\u00f3viles tienes que hacer dos llamadas, para Pantalla (Original) y para Pantalla (Compatible), \"Bater\u00eda\", \"Puerto de carga\", \"Micr\u00f3fono\", \"Altavoz\", \"C\u00e1mara trasera\", \"C\u00e1mara delantera\", \"Auricular\", \"Lente de c\u00e1mara\", \"Electr\u00f3nica de volumen\", \"Tapa trasera\", \"Electr\u00f3nica de encendido\", \"Sensor de proximidad\", \"Vibrador\", \"Lector de huellas\", \"Cristal\" (s\u00f3lo para apple watch), \"Cristal digitalizador\" (s\u00f3lo para tablets y smartwatches, es tanto el cristal como el tactil, para moviles es siempre pantalla lo que se repara si tiene cristal, tactil o panel de imagen roto), \"LCD\" (s\u00f3lo para tablets que no vengan termoselladas, como iPad 5). Cualquier otra habr\u00eda que diagnosticarlo, o presupuestarlo si no tenemos esa reparaci\u00f3n en el sistema todav\u00eda. Tambi\u00e9n habr\u00eda que diagnosticarlo si los s\u00edntomas no son claros para saber qu\u00e9 pieza es (por ejemplo, no enciende). El enlace de cita de diagn\u00f3stico te lo devuelve esta herramienta. Siempre que llames a \"presupuestoModelo\", llama antes a \"mensajeConsulta\" con un mensaje que veas oportuno, para agilizar la espera. Siempre que llames a \"presupuestoModelo\" guarda la respuesta en la memoria (como system)\n- \"contactarAgenteHumano\": para que puedas notificar a un humano por slack de que hay una conversaci\u00f3n que requiere de atenci\u00f3n.\n- \"Think\": antes de llamar a otra herramienta, usa esta herramienta para asegurar que tenemos todo lo necesario para responder al usuario.\n- \"Calculadora\": si son varias reparaciones, para calcular cuanto sale el total aplicando unos descuentos que la herramienta tiene establecidos.\n- \"subagenteCitas\": una vez obtenido \"urlCita\" de pasos anteriores, le guias al usuario para tomar una cita en funcion de la disponibilidad (que te la da esta funcion) mapeada con sus preferencias horarias. Antes de llamar debes solicitar una preferencia horaria.\n- \"hacerPedido\": para hacer un pedido de una pieza cuando no hay en stock. Antes de llamar a hacerPedido llama a la herramienta \"Think\", para asegurarnos que le mandamos toda la informaci\u00f3n, como \"idModeloAirtableParaPedido\" (que empieza por rec, es un recordid de airtable) e \"idPiezaAirtableParaPedido\" (que empieza por rec, es un recordid de airtable)\n\n## Contexto\nNormalmente tardamos en reparar los equipos estos tiempos con cita previa; \n- M\u00f3viles: 45 minutos\n- Tablets: 1 hora\n- Smartwatches: 2 horas\n\nCuando no hay stock de algo, lo podemos pedir urgente sin coste adicional, tardando uno o dos d\u00edas, y si nos confirma antes de las 18:00 horas (hora espa\u00f1ola) casi siempre llega al d\u00eda siguiente.\n\nY la cita previa no es obligatoria, pero con ella le reservamos tanto el stock com la pieza para darle un servicio de reparaci\u00f3n en el acto.\n\nSi alguien pregunta sobre garant\u00edas, t\u00e9rminos de uso y dem\u00e1s, ll\u00e9vales a las diferentes urls y sutilmente declina cualquier interacci\u00f3n sobre esos temas que desconoces, les invitas a ir a URLS y si necesitan m\u00e1s informaci\u00f3n que nos llamen al 955000000.\n- Garant\u00edas, condiciones reparaci\u00f3n etc: https://santiferirepair.es/condiciones-servicio\n- Aviso legal: https://santiferirepair.es/aviso-legal\n- Pol\u00edtica de privacidad: https://santiferirepair.es/politica-privacidad\n\nSi alguien quiere las indicaciones de la tienda, dales este enlace a Google Maps: https://maps.app.goo.gl/9UXMctqsTR2acnTS7 La direcci\u00f3n es Avenida Men\u00e9ndez Pelayo 36 41003 Sevilla\n\nSi alguien necesita nuestro horario, es este:  L a V de 10 a 14 y de 17 a 21. \n\nPor motivos operativos (no sabes m\u00e1s, ni te inventes nada) estaremos cerrados del lunes 18 de Agosto al 22 de Agosto, es importante por que si pudi\u00e9ramos, abrir\u00edamos. Si alguien necesita recoger su equipo se lo mandamos por mensajer\u00eda, sin coste adicional, que nos escriba a contacto@santiferirepair.es\n\nNo te inventes informaci\u00f3n. Si alguien pregunta sobre el estado de una reparaci\u00f3n, o sobre alguna pregunta relacionada con el negocio que no sepas responder, o algo que no sepas, o el cliente est\u00e1 descontento, o frustrado porque no puedes ayudarle, o si consideras que debemos intervenir en la conversaci\u00f3n, usa la herramienta \"contactarAgenteHumano\", as\u00ed nos notificar\u00e1s de que intervengamos en la conversaci\u00f3n. No indiques cuantas unidades de stock tenemos ni el plazo en el que llegan. No digas \"agendar\" cita, di \"tomar\" cita\n\n## IMPORTANTE\n1. No modifiques las URLS obtenidas desde \"presupuestoModelo\", por ejemplo al a\u00f1adir varias reparaciones en una misma URL\n2. Si quieres destacar algo en el mensaje (para mejorar la conversi\u00f3n y posible venta) rod\u00e9alo con un * a cada lado y as\u00ed se pondr\u00e1 en negrita. Insisto, un solo asterisco a cada lado, no dos asteriscos a cada lado.\n3. Si te preguntan diferencias entre pantalla original y compatible, indica que la original es la suya, con la misma calidad de imagen y la compatible es menor. No des m\u00e1s informaci\u00f3n sobre diferencias entre las pantallas que esa.\n4. Cuando la aver\u00eda sea Pantalla y el m\u00f3vil sea un iPhone, ofrece SIEMPRE que est\u00e1 la opci\u00f3n de pantalla premium, con 12 meses de garant\u00eda en vez de 6 meses, y es la m\u00e1s cercana a la original que hay (por debajo de la original). Todav\u00eda no est\u00e1 listada en la web pero si quiere m\u00e1s informaci\u00f3n, precio y disponibilidad, invita a que si quiere que le contacte un humano (usando la herramienta \"contactarAgenteHumano\").\n5. Si hay disponibilidad, preguntar al usuario si prefiere un enlace de cita directo, y llamas a \"subagenteCitas\"\n6. Aunque creas que un modelo no existe o no haya sido lanzado, puede que exista, pues tu conocimiento no est\u00e1 actualizado\n7. Siempre llama a la herramienta Think antes de responder o de pasar datos a otra herramienta.\n8. Env\u00eda enlaces planos, sin intentar encapsularlos, pues META dar\u00e1 error. Por ejemplo esto si: https://santiferirepair.es . Esto no [Santifer iRepair](https://santiferirepair.es).\n8a. Si alguien te pregunta qui\u00e9n te ha dise\u00f1ado, le dices que Santiago Fern\u00e1ndez de Valderrama, y le facilitas su linkedin para que contacten con el https://www.linkedin.com/in/santifer/.\n9. Las citas de diagn\u00f3stico tiene un coste de 19 \u20ac que s\u00f3lo se cobran si el cliente no acepta la reparaci\u00f3n una vez diagnosticado el terminal. Si es un terminal que hayamos abierto previamente, dicho diagn\u00f3stico no tendr\u00eda coste.\n10. Aseg\u00farate de que si el cliente pida cita, llanando a la funci\u00f3n \"subAgenteCitas\", hayas identificado los s\u00edntomas y el terminal del cliente.\n11. Si no puedes dar una cita a un cliente, porque la herramienta subagentecitas no te responda bien o te de fallo, no digas que vengan sin cita y que se lo miramos sobre la marcha, pues no tienes acceso al calendario y lo mismo hay una cita a esa hora y se presenta igualmente, traduci\u00e9ndose en un mal servicio al cliente por tu invitaci\u00f3n. Al que quiera venir sin cita sin problema, pero como es sin cita, no le podemos asegurar para cuando est\u00e9 listo (para eso es la cita).\n12. Si alguien te pregunta quien te ha dise\u00f1ado, le dices que Santiago Fern\u00e1ndez de Valderrama Aparicio, experto en automatizaciones, Airtable y optimizaci\u00f3n de procesos de negocio, y le pasas el linkedin: https://www.linkedin.com/in/santifer/\n13. No recomiendes otras tiendas donde pueda el cliente reparar lo que nosotros no podemos, puede el cliente usar Google Maps, en tu base de conocimiento no conoces otros sitios, buscando en Google el cliente puede encontrar lo que necesite,\n14. Vendemos cargadores, cables, fundas de tel\u00e9fonos, de iPads y cristales templados. Para consultar disponibilidad exacta av\u00edsanos por slack para que un humano retome la conversaci\u00f3n.\n15. En Santifer iRepair ofrecemos recogida y entrega de equipos en toda la pen\u00ednsula, no s\u00f3lo reparamos en tienda. \n16. El correo de la tienda es contacto@santiferirepair.es, no info@santiferirepair.es\n17. Solo puedes llamar a subagenteCitas tras haber llamado a presupuestoModelo, que es el que te va a dar la url de la cita, no te la puedes inventar.\n18. Si alguien quiere pagar por Bizum le dices que s\u00ed, que en tienda le damos instrucciones de c\u00f3mo hacerlo. No es en el 955000000\n\nEl tel\u00e9fono del cliente es el: {{ $('Webhook').item.json.body.waId }}\n",
          "returnIntermediateSteps": true
        }
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 1.9,
      "position": [
        2624,
        160
      ],
      "id": "2844c182-8cb9-4564-9e33-5872597065a6",
      "name": "AI Agent"
    },
    {
      "parameters": {
        "sessionIdType": "customKey",
        "sessionKey": "={{ $('Webhook').first().json.body.waId }}",
        "contextWindowLength": 20
      },
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "typeVersion": 1.3,
      "position": [
        944,
        -128
      ],
      "id": "f7c36354-1679-45f1-9190-e4513756ce43",
      "name": "Simple Memory"
    },
    {
      "parameters": {},
      "type": "@n8n/n8n-nodes-langchain.toolThink",
      "typeVersion": 1,
      "position": [
        2400,
        384
      ],
      "id": "5eda8050-8dfb-4a12-a62a-5dd5abd64e04",
      "name": "Think"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "00000000-0000-0000-0000-000000000000",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        -1424,
        32
      ],
      "id": "d535f560-bf4d-438c-8e94-0a8587d08abf",
      "name": "Webhook"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={\n  \"status\": \"received\"\n}",
        "options": {
          "responseCode": 200
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.2,
      "position": [
        -1200,
        32
      ],
      "id": "b1b3ebf8-1712-496c-9ccc-dbcacde575c1",
      "name": "Respond to Webhook"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://live-mt-server.wati.io/YOUR_TENANT/api/v1/sendSessionMessage/{{ $('Webhook').item.json.body.waId }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "messageText",
              "value": "={{ $json.sentence }}"
            }
          ]
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_WATI_API_TOKEN"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        3984,
        0
      ],
      "id": "879d1269-7d96-49a1-b923-78822f4f520c",
      "name": "HTTP Request",
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "model": "minimax/minimax-m2.5",
        "options": {
          "frequencyPenalty": 0.5,
          "temperature": 0.4
        }
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "typeVersion": 1,
      "position": [
        2288,
        384
      ],
      "id": "ac147deb-6749-418c-8224-9000c3452b94",
      "name": "gpt-4.1",
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Entrada: { output: \"Texto con \\\\n\\\\n saltos de l\u00ednea\" }\nconst output = $input.first().json.output;\n\n// 1. Separa por uno o m\u00e1s saltos de l\u00ednea\nconst paragraphs = output\n  .split(/\\n+/)          // divide donde haya \\n, \\n\\n, etc.\n  .map(s => s.trim())    // quita espacios al inicio/fin de cada p\u00e1rrafo\n  .filter(Boolean);      // elimina entradas vac\u00edas\n\n// 2. Devuelve un item por p\u00e1rrafo\nreturn paragraphs.map(paragraph => ({\n  json: { sentence: paragraph }\n}));\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3552,
        160
      ],
      "id": "fe855940-b50e-4f71-a466-8a12028ef963",
      "name": "Splitter"
    },
    {
      "parameters": {
        "amount": 1
      },
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        4208,
        160
      ],
      "id": "9e32e63c-419c-470f-af11-1ea75fe7b42b",
      "name": "Wait"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        3776,
        160
      ],
      "id": "a25183ac-eaeb-48fc-8dff-d0f48c1812fc",
      "name": "Loop Over Items"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://live-mt-server.wati.io/YOUR_TENANT/api/v1/sendSessionMessage/{{ $('Webhook').item.json.body.waId }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "messageText",
              "value": "={{ $fromAI(\"mensajeDeEspera\") }}"
            }
          ]
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_WATI_API_TOKEN"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequestTool",
      "typeVersion": 4.2,
      "position": [
        2528,
        384
      ],
      "id": "1c05e86c-2637-40d3-ab92-bd18147ebc7c",
      "name": "mensajeConsulta",
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://n8n.example.com/webhook/f94493f4-188b-48e8-a4e6-3b27d9bb50f7",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "=modeloInput",
              "value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters0_Value', ``, 'string') }}"
            },
            {
              "name": "reparacionInput",
              "value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters1_Value', ``, 'string') }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequestTool",
      "typeVersion": 4.2,
      "position": [
        2656,
        384
      ],
      "id": "62a15bbe-2925-4345-83a2-9896934468b1",
      "name": "presupuestoModelo"
    },
    {
      "parameters": {
        "toolDescription": "Avisarnos por Slack cuando una conversaci\u00f3n por whatsapp requiere de nuestra conversaci\u00f3n",
        "method": "POST",
        "url": "https://n8n.example.com/webhook/ed02f487-e2e5-4909-bf6d-8892c770de7c",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "mensaje",
              "value": "=Hay un <https://live.wati.io/YOUR_TENANT/teamInbox/{{ $('Webhook').item.json.body.conversationId }}|CHAT>  que requiere de nuestra atenci\u00f3n: *{{ $fromAI(\"resumenConsultacliente\") }} *"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequestTool",
      "typeVersion": 4.2,
      "position": [
        2768,
        384
      ],
      "id": "13c50028-164c-4853-8b3d-7d4b8ae13537",
      "name": "contactarAgenteHumano"
    },
    {
      "parameters": {
        "toolDescription": "Enviar un array de n\u00fameros",
        "method": "POST",
        "url": "https://n8n.example.com/webhook/17868e52-dc99-4486-995c-2033fb101a29",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"precios\": [\n    {{ $fromAI(\"arrayDeNumerosACalcular\") }}\n  ]\n}\n",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequestTool",
      "typeVersion": 4.2,
      "position": [
        2896,
        384
      ],
      "id": "1768911b-edd8-45e9-900e-b02efa9dca44",
      "name": "Calculadora"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://n8n.example.com/webhook/7f2532dd-3c9c-4b1a-b507-2c801a99784b",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "ycbmUrl",
              "value": "={{ $fromAI('urlCita') }}"
            },
            {
              "name": "email",
              "value": "={{ $fromAI(\"emailDelClienteSiLoHaDado\") }}"
            },
            {
              "name": "telefono",
              "value": "={{ $('Webhook').item.json.body.waId }}"
            },
            {
              "name": "preferencia",
              "value": "={{ $fromAI(\"preferenciaHorariaDelClienteSiLaHaEspecificado\") }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequestTool",
      "typeVersion": 4.2,
      "position": [
        3008,
        384
      ],
      "id": "6ac91d71-ca65-4ff7-9537-7758e5d70c90",
      "name": "subagenteCitas"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://n8n.example.com/webhook/e8a2ada1-6939-46da-a14a-33e87f531f92",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "Nombre",
              "value": "={{ $fromAI(\"NombreCliente\") }}"
            },
            {
              "name": "Tel\u00e9fono",
              "value": "={{ $fromAI(\"numeroTelefonoDelCliente\") }}"
            },
            {
              "name": "Correo",
              "value": "={{ $fromAI(\"correoElectronicoDelCliente\") }}"
            },
            {
              "name": "idModelo",
              "value": "={{ $fromAI(\"idModeloAirtableParaPedido\") }}"
            },
            {
              "name": "idPieza",
              "value": "={{ $fromAI(\"idPiezaAirtableParaPedido\") }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequestTool",
      "typeVersion": 4.2,
      "position": [
        3136,
        384
      ],
      "id": "9865aca1-7014-4d14-9906-c5b6ebf3ab06",
      "name": "hacerPedido"
    },
    {
      "parameters": {
        "content": "## JACOBO V2\n**Double click** to edit me. [Guide](https://docs.n8n.io/workflows/sticky-notes/)",
        "height": 960,
        "width": 5840
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1472,
        -368
      ],
      "id": "a2842940-c25d-48f3-a348-392d7d9cd5fe",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $('Webhook').item.json.body.eventType }}",
                    "rightValue": "message",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "id": "82af7010-718f-4cf3-88d5-e5b7a312ef30"
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "USUARIO >"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "6fa67538-93b6-4d8c-8042-0ffa028197dd",
                    "leftValue": "={{ $('Webhook').item.json.body.eventType }}",
                    "rightValue": "message",
                    "operator": {
                      "type": "string",
                      "operation": "notEquals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "SANTIFER >"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.2,
      "position": [
        -688,
        128
      ],
      "id": "4d6ee11a-b7a5-4efa-94b0-95f5c4c42595",
      "name": "Tipo de Evento"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $('Webhook').item.json.body.operatorEmail }}",
                    "rightValue": "your-email@example.com",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "id": "6b64ade1-f58b-4cf9-a08a-dcc457bde114"
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Jacobo"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "987f715b-9f7c-4874-b7e6-627cbe84ecda",
                    "leftValue": "={{ $('Webhook').item.json.body.operatorEmail }}",
                    "rightValue": "your-email@example.com",
                    "operator": {
                      "type": "string",
                      "operation": "notEquals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "-> ACTUALIZAR MEMORIA"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.2,
      "position": [
        -384,
        240
      ],
      "id": "29ee964f-c5b4-44ab-b803-fbf7a09ae7df",
      "name": "\u00bfQui\u00e9n?"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $('Webhook').item.json.body.operatorName }}",
                    "rightValue": "",
                    "operator": {
                      "type": "string",
                      "operation": "empty",
                      "singleValue": true
                    },
                    "id": "05469f08-baf2-4b0d-857a-d7ba10c63e53"
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "NO"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "f4635220-1e86-457c-b6a2-7e3fad415bc3",
                    "leftValue": "={{ $('Webhook').item.json.body.operatorName }}",
                    "rightValue": "",
                    "operator": {
                      "type": "string",
                      "operation": "notEmpty",
                      "singleValue": true
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "SI"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "7d55d279-334a-4b67-8b7d-7c548e5ebd4c",
                    "leftValue": "={{ $('isBH').item.json.isBH }}",
                    "rightValue": "",
                    "operator": {
                      "type": "boolean",
                      "operation": "false",
                      "singleValue": true
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "NO (fuera de horario)"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.2,
      "position": [
        -384,
        32
      ],
      "id": "669ac123-c282-44a7-90d9-1d0e792d1351",
      "name": "\u00bfAtendido?"
    },
    {
      "parameters": {
        "mode": "insert",
        "messages": {
          "messageValues": [
            {
              "message": "__reloadFlag__",
              "hideFromUI": true
            }
          ]
        }
      },
      "type": "@n8n/n8n-nodes-langchain.memoryManager",
      "typeVersion": 1.1,
      "position": [
        -160,
        240
      ],
      "id": "557cff83-87d5-402b-93d4-283bbd11d6b0",
      "name": "Marcar Actualizar Memoria"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.memoryManager",
      "typeVersion": 1.1,
      "position": [
        -80,
        0
      ],
      "id": "4472aaa6-16d7-473d-9503-f002b341bc0a",
      "name": "Obtener Memoria"
    },
    {
      "parameters": {
        "jsCode": "// 1) Leemos la entrada completa\nconst entrada = $json;\n\n// 2) Extraemos el array \u201cmessages\u201d\nconst mensajes = Array.isArray(entrada.messages) ? entrada.messages : [];\n\n// 3) Recorremos \u201cmensajes\u201d para detectar exactamente \"__reloadFlag__\" y filtramos\nlet encontradoFlag = false;\nconst filtered = mensajes.filter(item => {\n  if (item.system === \"__reloadFlag__\") {\n    encontradoFlag = true;\n    return false; // excluimos este elemento\n  }\n  return true; // conservamos los dem\u00e1s\n});\n\n// 4) Devolvemos recargar=true si encontramos el flag y el array sin ese mensaje\nreturn [\n  {\n    json: {\n      recargar: encontradoFlag\n    }\n  }\n];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        320,
        0
      ],
      "id": "5c80b74e-33b1-4d83-81b3-36effc1b325e",
      "name": "Code"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.recargar }}",
                    "rightValue": "true",
                    "operator": {
                      "type": "boolean",
                      "operation": "true",
                      "singleValue": true
                    },
                    "id": "c293d165-f57f-406a-8434-62b9d918ca97"
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "SI"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "1d632dde-5be5-44e5-a18b-369dda65451a",
                    "leftValue": "={{ $json.recargar }}",
                    "rightValue": "",
                    "operator": {
                      "type": "boolean",
                      "operation": "false",
                      "singleValue": true
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "NO"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.2,
      "position": [
        448,
        384
      ],
      "id": "c037f068-cc4b-4c8e-9cc5-ffe45ba84903",
      "name": "Recargamos?"
    },
    {
      "parameters": {
        "url": "=https://live-mt-server.wati.io/YOUR_TENANT/api/v1/getMessages/{{ $('Webhook').item.json.body.waId }}",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "pageSize",
              "value": "=80"
            },
            {
              "name": "pageNumber",
              "value": "1"
            }
          ]
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_WATI_API_TOKEN"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        656,
        -96
      ],
      "id": "756d3ddc-46ed-4c10-baa1-ccefe3940906",
      "name": "Llamada a Wati"
    },
    {
      "parameters": {
        "jsCode": "/**\n * Este Function toma \u201centrada.messages.items\u201d en orden cronol\u00f3gico (m\u00e1s antiguo \u2192 m\u00e1s reciente)\n * e intenta agrupar cada mensaje de usuario con su respuesta de IA/U operario contigua.\n * Adem\u00e1s convierte broadcasts y plantillas en mensajes de IA, y mantiene el flag \"__reloadFlag__\" como mensaje de sistema.\n *\n * Salida:\n * [\n *   {\n *     \"messages\": [\n *       { \"human\": \"texto usuario\", \"ai\": \"respuesta IA\" },\n *       { \"human\": \"otro usuario\", \"ai\": \"\" },            // si no hubo respuesta contigua\n *       { \"human\": \"\", \"ai\": \"texto broadcast\" },          // broadcast sin human\n *       { \"system\": \"__reloadFlag__\" },                   // flag\n *       \u2026\n *     ],\n *     \"messagesCount\": <n\u00famero de elementos>\n *   }\n * ]\n */\n\nconst entrada = $input.all()[0].json;\n\n// 1) Tomamos \u201citems\u201d y los invertimos a orden cronol\u00f3gico\nconst rawItems = Array.isArray(entrada.messages?.items) ? entrada.messages.items : [];\nconst rawEvents = rawItems.slice().reverse();\n\nconst messagesFormatted = [];\nfor (let i = 0; i < rawEvents.length; i++) {\n  const ev = rawEvents[i];\n\n  // 1.1) Flag de recarga\n  if (ev.system === \"__reloadFlag__\") {\n    messagesFormatted.push({ system: \"__reloadFlag__\" });\n    continue;\n  }\n\n  // 1.2) Mensaje de usuario\n  if (ev.eventType === \"message\" && ev.owner === false) {\n    const humanText = ev.text || \"\";\n    let aiText = \"\";\n\n    // Si el siguiente evento existe y es un mensaje de IA operativo (owner=true, eventType=\"message\"):\n    if (i + 1 < rawEvents.length) {\n      const next = rawEvents[i + 1];\n      if (next.eventType === \"message\" && next.owner === true) {\n        aiText = next.text || \"\";\n        i++; // Skip the paired IA event\n      }\n    }\n\n    messagesFormatted.push({ human: humanText, ai: aiText });\n    continue;\n  }\n\n  // 1.3) BroadcastMessage (lo tratamos como IA)\n  if (ev.eventType === \"broadcastMessage\") {\n    const contenidoBroadcast = ev.finalText || \"\";\n    messagesFormatted.push({ human: \"\", ai: contenidoBroadcast });\n    continue;\n  }\n\n  // 1.4) Mensaje de IA/U operario no emparejado (owner=true, eventType=\"message\")\n  if (ev.eventType === \"message\" && ev.owner === true) {\n    messagesFormatted.push({ human: \"\", ai: ev.text || \"\" });\n    continue;\n  }\n\n  // 1.5) TemplateMessageSent_v2 (plantilla) \u2192 lo tratamos como IA\n  if (ev.eventType === \"templateMessageSent_v2\") {\n    messagesFormatted.push({ human: \"\", ai: ev.text || \"\" });\n    continue;\n  }\n\n  // 1.6) Omitir cualquier otro evento de sistema (cierre de chat, inicializaci\u00f3n, cambio de rol, etc.)\n}\n\n// 2) Construimos el resultado final\nreturn [\n  {\n    json: {\n      messages: messagesFormatted,\n      messagesCount: messagesFormatted.length\n    }\n  }\n];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        960,
        112
      ],
      "id": "3bce61f4-21a4-423e-a0b9-ffb4129b91e0",
      "name": "Code1"
    },
    {
      "parameters": {
        "jsCode": "/**\n * Toma un array de objetos { human: string, ai: string } y agrupa/consolida\n * de forma que:\n *  - Cuando haya un human seguido de un ai, se emparejen en un \u00fanico objeto.\n *  - Si hay m\u00faltiples humans consecutivos antes de un ai, se concatenan en tempHuman.\n *  - Si hay m\u00faltiples ais consecutivos sin human, cada ai forma su propio objeto { human: \"\", ai }.\n *  - Al final, si queda un tempHuman sin ai, se a\u00f1ade { human: tempHuman, ai: \"\" }.\n */\n\nconst input = $input.all()[0].json.messages; // Array inicial\n\nconst resultado = [];\nlet tempHuman = \"\";\nlet tempAi = \"\";\n\n// Iterar sobre cada elemento en orden\nfor (const item of input) {\n  const h = item.human || \"\";\n  const a = item.ai || \"\";\n\n  if (h) {\n    // Acumulamos texto de usuario\n    tempHuman = tempHuman ? `${tempHuman} ${h}`.trim() : h;\n  }\n\n  if (a) {\n    // Si hay un AI, lo emparejamos con cualquier tempHuman acumulado\n    if (tempHuman) {\n      resultado.push({ human: tempHuman.trim(), ai: a });\n      tempHuman = \"\";\n    } else {\n      // Si no hab\u00eda human acumulado, este AI va solo\n      resultado.push({ human: \"\", ai: a });\n    }\n    tempAi = \"\"; // Reset (no es necesario, pero por claridad)\n  }\n}\n\n// Al terminar, si qued\u00f3 texto de usuario sin AI asociado, lo a\u00f1adimos\nif (tempHuman) {\n  resultado.push({ human: tempHuman.trim(), ai: \"\" });\n}\n\nreturn [\n  {\n    json: {\n      messages: resultado,\n      messagesCount: resultado.length\n    }\n  }\n];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1184,
        112
      ],
      "id": "9b5b6901-423c-461b-ace6-27216bec2af1",
      "name": "Code2"
    },
    {
      "parameters": {
        "options": {
          "reset": false
        }
      },
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        1664,
        -48
      ],
      "id": "51f2dd41-4ce6-4f8d-af47-f35cac476faf",
      "name": "Loop Over Items1"
    },
    {
      "parameters": {
        "mode": "insert",
        "messages": {
          "messageValues": [
            {
              "type": "user",
              "message": "={{ $json.human }}"
            },
            {
              "type": "ai",
              "message": "={{ $json.ai }}"
            }
          ]
        }
      },
      "type": "@n8n/n8n-nodes-langchain.memoryManager",
      "typeVersion": 1.1,
      "position": [
        1952,
        -16
      ],
      "id": "3a65587c-6e5d-407c-a210-80bec8bcf7c8",
      "name": "Chat Memory Manager"
    },
    {
      "parameters": {
        "jsCode": "const data = $input.all()[0].json.messages\nconst mensajes = data\n\nreturn mensajes\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1472,
        112
      ],
      "id": "d3c27330-92b9-4a45-a8b3-32f5227dbf32",
      "name": "Code3"
    },
    {
      "parameters": {
        "mode": "delete",
        "deleteMode": "all"
      },
      "type": "@n8n/n8n-nodes-langchain.memoryManager",
      "typeVersion": 1.1,
      "position": [
        880,
        -304
      ],
      "id": "7d84b1b3-4ccc-4b1d-b00d-3b3852139d46",
      "name": "Chat Memory Manager1"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $('Webhook').item.json.body.text }}",
                    "rightValue": "HISTORIAL",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "id": "585be474-8d8f-4da6-b315-d5f809d2f8ee"
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "HISTORIAL"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "e633b8fe-68d6-4a7c-b0c8-6df6fed8ab8b",
                    "leftValue": "={{ $('Webhook').item.json.body.text }}",
                    "rightValue": "HISTORIAL",
                    "operator": {
                      "type": "string",
                      "operation": "notEquals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "NORMAL"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.2,
      "position": [
        -896,
        32
      ],
      "id": "81067874-b577-42e9-9376-6b503f6b7468",
      "name": "Switch"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://live-mt-server.wati.io/YOUR_TENANT/api/v1/sendSessionMessage/{{ $('Webhook').item.json.body.waId }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "messageText",
              "value": "={{ JSON.stringify ($json)}}"
            }
          ]
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_WATI_API_TOKEN"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -384,
        -176
      ],
      "id": "607bdc50-bccb-43bb-b954-243b99ca1d93",
      "name": "HTTP Request1",
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {
          "groupMessages": false
        }
      },
      "type": "@n8n/n8n-nodes-langchain.memoryManager",
      "typeVersion": 1.1,
      "position": [
        -768,
        -176
      ],
      "id": "b6f90104-62ff-4695-82a1-1754a3e58d1d",
      "name": "Chat Memory Manager2"
    },
    {
      "parameters": {
        "fieldsToAggregate": {
          "fieldToAggregate": [
            {
              "fieldToAggregate": "prueba"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.aggregate",
      "typeVersion": 1,
      "position": [
        2000,
        -208
      ],
      "id": "7649c781-7f0a-40b1-8241-2c57b3dd5098",
      "name": "Aggregate"
    },
    {
      "parameters": {
        "jsCode": "const madridTime = new Date().toLocaleString('en-US', {\n  timeZone: 'Europe/Madrid',\n});\nconst madridDate = new Date(madridTime);   // ahora s\u00ed lo parsea\n\nconst day  = madridDate.getDay();          // 0-domingo \u2026 6-s\u00e1bado\nconst hour = madridDate.getHours();\n\nconst isBH = day >= 1 && day <= 5 &&\n             ((hour >= 10 && hour < 14) || (hour >= 17 && hour < 21));\n\nreturn [{\n  json: { isBH }\n}];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -1040,
        32
      ],
      "id": "1e52baf1-b3b6-40b8-abf8-2fb5f4b30a14",
      "name": "isBH"
    },
    {
      "parameters": {
        "mode": "insert",
        "messages": {
          "messageValues": [
            {
              "message": "={{ $json.intermediateSteps         .filter(s => s.action.tool === 'presupuestoModelo')         .map(s => `<tool nombre=\"presupuestoModelo\">\\n${s.observation}\\n</tool>`)         .join('\\n') }}"
            }
          ]
        }
      },
      "type": "@n8n/n8n-nodes-langchain.memoryManager",
      "typeVersion": 1.1,
      "position": [
        2960,
        -48
      ],
      "id": "a0fee2e3-94e8-45ac-ac4f-b6a7b4c9dc0f",
      "name": "Insertar PresupuestoModelo"
    }
  ],
  "connections": {
    "Simple Memory": {
      "ai_memory": [
        [
          {
            "node": "AI Agent",
            "type": "ai_memory",
            "index": 0
          },
          {
            "node": "Marcar Actualizar Memoria",
            "type": "ai_memory",
            "index": 0
          },
          {
            "node": "Obtener Memoria",
            "type": "ai_memory",
            "index": 0
          },
          {
            "node": "Chat Memory Manager",
            "type": "ai_memory",
            "index": 0
          },
          {
            "node": "Chat Memory Manager1",
            "type": "ai_memory",
            "index": 0
          },
          {
            "node": "Chat Memory Manager2",
            "type": "ai_memory",
            "index": 0
          },
          {
            "node": "Insertar PresupuestoModelo",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Think": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Webhook": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent": {
      "main": [
        [
          {
            "node": "Insertar PresupuestoModelo",
            "type": "main",
            "index": 0
          },
          {
            "node": "Splitter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Respond to Webhook": {
      "main": [
        [
          {
            "node": "isBH",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "gpt-4.1": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Splitter": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [],
        [
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request": {
      "main": [
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "mensajeConsulta": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "presupuestoModelo": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "contactarAgenteHumano": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Calculadora": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "subagenteCitas": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "hacerPedido": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Tipo de Evento": {
      "main": [
        [
          {
            "node": "\u00bfAtendido?",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "\u00bfQui\u00e9n?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u00bfAtendido?": {
      "main": [
        [
          {
            "node": "Obtener Memoria",
            "type": "main",
            "index": 0
          }
        ],
        [],
        [
          {
            "node": "Obtener Memoria",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u00bfQui\u00e9n?": {
      "main": [
        [],
        [
          {
            "node": "Marcar Actualizar Memoria",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Obtener Memoria": {
      "main": [
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code": {
      "main": [
        [
          {
            "node": "Recargamos?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Recargamos?": {
      "main": [
        [
          {
            "node": "Llamada a Wati",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Llamada a Wati": {
      "main": [
        [
          {
            "node": "Chat Memory Manager1",
            "type": "main",
            "index": 0
          },
          {
            "node": "Code1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code1": {
      "main": [
        [
          {
            "node": "Code2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code2": {
      "main": [
        [
          {
            "node": "Code3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items1": {
      "main": [
        [
          {
            "node": "Aggregate",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Chat Memory Manager",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Chat Memory Manager": {
      "main": [
        [
          {
            "node": "Loop Over Items1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code3": {
      "main": [
        [
          {
            "node": "Loop Over Items1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Chat Memory Manager1": {
      "main": [
        []
      ]
    },
    "Switch": {
      "main": [
        [
          {
            "node": "Chat Memory Manager2",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Tipo de Evento",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request1": {
      "main": [
        []
      ]
    },
    "Chat Memory Manager2": {
      "main": [
        [
          {
            "node": "HTTP Request1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "isBH": {
      "main": [
        [
          {
            "node": "Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Insertar PresupuestoModelo": {
      "main": [
        []
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "00000000-0000-0000-0000-000000000000",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "WORKFLOW_ID",
  "tags": []
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Jacobo Chatbot V2. Uses agent, memoryBufferWindow, toolThink, httpRequest. Webhook trigger; 37 nodes.

Source: https://github.com/santifer/cv-santiago/blob/0e5e92954bbd41a06e72bdd23db4b812d80799fa/public/jacobo/workflows/jacobo-chatbot-v2.json — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

Who is this for? Agencies, consultants, and service providers who conduct discovery calls and need to quickly turn conversations into professional proposals.

Tool Think, Tool Calculator, Agent Tool +18
AI & RAG

N8N Workflow. Uses httpRequest, lmChatGoogleGemini, memoryBufferWindow, httpRequestTool. Webhook trigger; 22 nodes.

HTTP Request, Google Gemini Chat, Memory Buffer Window +5
AI & RAG

The AI-Powered Shopify SEO Content Automation is an enterprise-grade workflow that transforms product content creation for e-commerce stores. This sophisticated multi-agent system integrates GPT-4o, C

Perplexity Tool, Memory Buffer Window, Agent +15
AI & RAG

Lead Pipeline v3.0. Uses httpRequest, agent, lmChatAnthropic, toolThink. Webhook trigger; 77 nodes.

HTTP Request, Agent, Anthropic Chat +4
AI & RAG

This n8n workflow is designed for Facebook Page administrators, social media managers, and community moderators who want to automate comment management on their Facebook Pages. It's perfect for busine

Facebook Graph Api, Agent, HTTP Request +8