{"id":"wVfxcbqFblPvcbpK","meta":{"instanceId":"fc542c1c50834db93f4c2ec54f0b22e845aa07e55bbdcab4ae51fd60fe13f015","templateCredsSetupCompleted":true},"name":"n8n - Agent with Memory and Strategy","tags":[],"nodes":[{"id":"481dfc28-ff80-4041-b160-b3a793228a39","name":"Code in JavaScript","type":"n8n-nodes-base.code","position":[-160,-864],"parameters":{"jsCode":"// Este código solo extrae el texto del mensaje y el chat_id de manera garantizada.\n\n// 1. Extraer el texto del usuario\nconst chatMessage = $json.message.text || \"\";\n\n// 2. Extraer el ID del chat\nconst chatId = $json.message.chat.id || 0;\n\n// 3. Devolver un objeto limpio con solo los datos que el flujo necesita.\n// Esto garantiza que el AI Agent reciba el texto como '$json.text' y el ID como '$json.chat_id'.\nreturn [\n    {\n        json: {\n            text: chatMessage,\n            chat_id: chatId\n        }\n    }\n];"},"typeVersion":2},{"id":"824a2fe4-81cf-437b-af4e-529b90666055","name":"Telegram Trigger","type":"n8n-nodes-base.telegramTrigger","position":[-432,-864],"webhookId":"80b6801c-e25c-46f3-82b6-e1a6d9c9f819","parameters":{"updates":["message"],"additionalFields":{}},"credentials":{"telegramApi":{"id":"RS6xBLhzi9OjHy7E","name":"Telegram account"}},"typeVersion":1.2},{"id":"97b40d4f-b79f-47b4-b996-3abdcc176cd2","name":"Send a text message","type":"n8n-nodes-base.telegram","position":[1344,-864],"webhookId":"727b538c-4185-48f0-82b1-9e1123877594","parameters":{"text":"={{ $json.response }}","chatId":"={{ $('Code in JavaScript').first().json.chat_id }}","additionalFields":{}},"credentials":{"telegramApi":{"id":"RS6xBLhzi9OjHy7E","name":"Telegram account"}},"typeVersion":1.2},{"id":"0c5c9907-652d-4dab-a6c4-fab1521da07a","name":"OpenAI Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[448,-576],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini","cachedResultName":"gpt-4o-mini"},"options":{},"builtInTools":{}},"credentials":{"openAiApi":{"id":"J1PaeSb05uBb3olU","name":"OpenAi account"}},"typeVersion":1.3},{"id":"c51b8e6a-99af-4b48-8d01-1c8423acc3f1","name":"AI Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[528,-864],"parameters":{"text":"={{ $('Telegram Trigger').item.json.message.text }}","options":{"systemMessage":"=Eres SOFÍA, la barista experta y proactiva de Zyntha Coffee. Tu misión es guiar al usuario en una experiencia personalizada utilizando la memoria de Postgres y los productos de Shopify.\n\nPROTOCOLO DE BIENVENIDA (OBLIGATORIO):\n1. Revisa el historial. Si NO conoces el nombre del usuario:\n   - Tu ÚNICA respuesta debe ser saludar y preguntar: \"¡Hola! Soy Sofía, tu barista virtual. Antes de empezar, ¿me podrías decir tu nombre para atenderte mejor?\".\n   - NO des información de cafés hasta tener el nombre.\n2. Si ya conoces el nombre (ej: Diego):\n   - Salúdalo siempre por su nombre y pregúntale qué perfil de sabor busca hoy.\n\nREGLA DE PRECISIÓN EN EL CATÁLOGO:\n- Si el usuario pregunta qué cafés hay o pide opciones, DEBES listar los nombres exactos y precios que aparecen en la sección de PRODUCTOS abajo.\n- Prohibido decir \"tenemos una variedad\" sin dar nombres específicos.\n\nREGLA DE FOCO:\n- Si se habla de un café específico (ej: CASTILLO), toda la información técnica y de preparación debe ser sobre ese café únicamente.\n\nFORMATO DE SALIDA (JSON):\n{\n  \"intent\": \"setup | recommendation | question\",\n  \"response\": \"Tu respuesta humana aquí...\",\n  \"product\": \"Nombre del café en discusión o null\",\n  \"qty\": null\n}\n\nPRODUCTOS DISPONIBLES (SHOPIFY):\n{{ $('Get many products').all().map(p => p.json.title + \" (Precio: $\" + p.json.variants[0].price + \")\").join(', ') }}\n\nREGLA DE MEMORIA TOTAL:\n1. Antes de responder, analiza TODO el historial recuperado de Postgres.\n2. Identifica y recuerda: \n   - Nombre del usuario.\n   - Cafés por los que ha preguntado (ej: Caturra, Castillo).\n   - Preferencias de sabor (dulce, ácido, etc.).\n3. Si el usuario dice \"Hola\", no uses el protocolo de bienvenida si ya hay información previa. Di: \"¡Hola [Nombre]! Qué bueno verte de nuevo. ¿Seguimos hablando del café [Último café mencionado] o quieres probar algo más [Gusto del usuario]?\"\n4. NUNCA digas que no sabes algo que ya se mencionó en el chat."},"promptType":"define","hasOutputParser":true},"typeVersion":3},{"id":"e82ddd5b-060b-4fe1-9368-45427751d300","name":"Get many products","type":"n8n-nodes-base.shopify","position":[128,-864],"parameters":{"resource":"product","operation":"getAll","authentication":"oAuth2","additionalFields":{}},"credentials":{"shopifyOAuth2Api":{"id":"thezIuSeAIHhsOpm","name":"Shopify Access Token account"}},"typeVersion":1},{"id":"6b457ea9-4f40-4c3b-bf91-6ee8d20c70e0","name":"Postgres Chat Memory","type":"@n8n/n8n-nodes-langchain.memoryPostgresChat","position":[608,-592],"parameters":{"sessionKey":"={{ $('Code in JavaScript').item.json.chat_id }}","sessionIdType":"customKey","contextWindowLength":30},"credentials":{"postgres":{"id":"J3jIJ3COBTMJhmj2","name":"Postgres account 2"}},"typeVersion":1.3},{"id":"e3e1281d-4353-4e41-83a8-1e6e341e3872","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[-1184,-1296],"parameters":{"width":576,"height":496,"content":"## AI Advisor with Memory and Real-Time Context\n\n### How it works\nThis workflow turns a generic chatbot into an AI advisor that remembers users and responds using real business data.\n\nIt combines user messages, persistent memory, and live product data to generate accurate and human-like responses.\n\n### How to set up\n1. Import the workflow into n8n.\n2. Connect the required credentials (Telegram, OpenAI, Shopify, Postgres).\n3. Configure the database connection for chat memory.\n4. Test the flow by sending a message from Telegram.\n\n### Customization\n• Adjust the system message to match your tone or industry.\n• Replace Shopify with another data source if needed.\n• Change the memory window size depending on your use case.\n"},"typeVersion":1},{"id":"7e4c6da8-895b-43f8-a3c3-5aad74b63561","name":"Sticky Note8","type":"n8n-nodes-base.stickyNote","position":[-464,-1168],"parameters":{"color":7,"width":432,"height":480,"content":"## Section 1 — Input & User Identification\n\nReceives the incoming message and extracts the chat_id used to uniquely identify the user.\n\nThis ensures every message can be linked to the correct conversation history.\n"},"typeVersion":1},{"id":"808a70ec-8092-4c8c-ba29-8e950bbb5e39","name":"Sticky Note9","type":"n8n-nodes-base.stickyNote","position":[0,-1168],"parameters":{"color":7,"width":336,"height":512,"content":"## Section 2 — Real-Time Context\n\nFetches the live product catalog directly from the store.\n\nThis prevents the AI from hallucinating product names or prices.\n"},"typeVersion":1},{"id":"9d6f718e-b2ab-4c67-aec9-339a85512863","name":"Sticky Note10","type":"n8n-nodes-base.stickyNote","position":[368,-1168],"parameters":{"color":7,"width":512,"height":720,"content":"## Section 3 — AI Reasoning & Memory\n\nCombines user input, historical memory, and real-time data to generate a contextual response.\n\nThis is where personalization, rules, and long-term memory are applied."},"typeVersion":1},{"id":"0120d21c-e550-4e57-9030-66779283d6ef","name":"Sticky Note11","type":"n8n-nodes-base.stickyNote","position":[928,-1168],"parameters":{"color":7,"width":704,"height":544,"content":"## Section 4 — Output & Delivery\n\nValidates that the AI response is valid JSON and applies a fallback if needed.\n\nSends the final, safe response back to the user via Telegram.\n"},"typeVersion":1},{"id":"e5d3f936-e207-40f1-a51e-54d07bcc1632","name":"Code in JavaScript 2","type":"n8n-nodes-base.code","position":[1088,-864],"parameters":{"jsCode":"// Obtenemos la salida del AI Agent\nlet rawResponse = items[0].json.output;\n\ntry {\n  // 1. Intentamos buscar un JSON dentro de la respuesta (por si la IA escribió texto extra)\n  const start = rawResponse.indexOf('{');\n  const end = rawResponse.lastIndexOf('}');\n  \n  if (start !== -1 && end !== -1) {\n    let jsonString = rawResponse.substring(start, end + 1);\n    let parsed = JSON.parse(jsonString);\n    \n    // Si el JSON es válido, lo retornamos tal cual\n    return parsed;\n  }\n  \n  // 2. Si no hay llaves { }, lanzamos un error para ir al bloque 'catch'\n  throw new Error(\"No JSON format found\");\n\n} catch (e) {\n  // 3. RESPUESTA DE SEGURIDAD: Si algo falla, forzamos el protocolo de bienvenida\n  // Esto evita el mensaje de \"me distraje con el aroma\"\n  return {\n    \"intent\": \"setup\",\n    \"response\": \"¡Hola! Soy Sofía, tu barista de Zyntha Coffee. Antes de empezar a hablar de café, me encantaría saber tu nombre para atenderte mejor. ¿Cómo te llamas?\",\n    \"product\": null,\n    \"qty\": null\n  };\n}"},"typeVersion":2},{"id":"2c15000e-c941-4b79-af53-32bf3ae07009","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[1280,-672],"parameters":{"color":3,"width":272,"height":192,"content":"⚠️ Important\n\nThis workflow requires valid JSON output from the AI.\n\nIf you modify the system prompt, make sure the response format is preserved to avoid parsing errors.\n"},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"de9e54b3-1362-4ce9-9709-4fc37c1b21ff","connections":{"AI Agent":{"main":[[{"node":"Code in JavaScript 2","type":"main","index":0}]]},"Telegram Trigger":{"main":[[{"node":"Code in JavaScript","type":"main","index":0}]]},"Get many products":{"main":[[{"node":"AI Agent","type":"main","index":0}]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"AI Agent","type":"ai_languageModel","index":0}]]},"Code in JavaScript":{"main":[[{"node":"Get many products","type":"main","index":0}]]},"Code in JavaScript 2":{"main":[[{"node":"Send a text message","type":"main","index":0}]]},"Postgres Chat Memory":{"ai_memory":[[{"node":"AI Agent","type":"ai_memory","index":0}]]}}}