{
  "nodes": [
    {
      "parameters": {},
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        5760,
        2096
      ],
      "id": "32b90cc2-3d22-4b7f-b2ad-645e2eaff59a",
      "name": "When clicking Execute workflow"
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        5760,
        1904
      ],
      "id": "54eca99c-2bd8-41a7-a5c2-cbf05d712b4f",
      "name": "Schedule Trigger"
    },
    {
      "parameters": {
        "url": "https://www.theguardian.com/environment/climate-crisis/rss",
        "options": {}
      },
      "type": "n8n-nodes-base.rssFeedRead",
      "typeVersion": 1.2,
      "position": [
        6000,
        1904
      ],
      "id": "6a04d325-c42e-4ba1-98f4-fbfbc6d28121",
      "name": "RSS Read"
    },
    {
      "parameters": {
        "url": "https://grist.org/feed/",
        "options": {}
      },
      "type": "n8n-nodes-base.rssFeedRead",
      "typeVersion": 1.2,
      "position": [
        6208,
        1904
      ],
      "id": "0ab5d01e-c9f3-45e4-b664-fe84bb564709",
      "name": "RSS Read1"
    },
    {
      "parameters": {
        "url": "https://insideclimatenews.org/feed/",
        "options": {}
      },
      "type": "n8n-nodes-base.rssFeedRead",
      "typeVersion": 1.2,
      "position": [
        6416,
        1904
      ],
      "id": "0907d7f3-0249-4f14-b679-b11bd1aa08be",
      "name": "RSS Read2"
    },
    {
      "parameters": {
        "numberInputs": 3
      },
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3.2,
      "position": [
        6624,
        1904
      ],
      "id": "4c8c3232-f45b-4790-bc83-190f5f7a6569",
      "name": "Merge"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "a1",
              "name": "title",
              "value": "={{ $json.title }}",
              "type": "string"
            },
            {
              "id": "a2",
              "name": "link",
              "value": "={{ $json.link }}",
              "type": "string"
            },
            {
              "id": "a3",
              "name": "snippet",
              "value": "={{ ($json.contentSnippet || $json.content || '').slice(0, 200) }}",
              "type": "string"
            },
            {
              "id": "a4",
              "name": "date",
              "value": "={{ $json.isoDate || $json.pubDate }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        6832,
        1904
      ],
      "id": "08435dce-616c-4fc9-8c59-31cd97663fea",
      "name": "Edit Fields"
    },
    {
      "parameters": {
        "compare": "selectedFields",
        "fieldsToCompare": "link",
        "options": {}
      },
      "type": "n8n-nodes-base.removeDuplicates",
      "typeVersion": 2,
      "position": [
        7008,
        1904
      ],
      "id": "8d30005e-1732-461a-9c06-41a2b7a49d4a",
      "name": "Remove Duplicates"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "f1",
              "leftValue": "={{ new Date($json.date) > $now.minus({ days: 7 }).toJSDate() }}",
              "rightValue": "=",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.filter",
      "typeVersion": 2.3,
      "position": [
        7216,
        1904
      ],
      "id": "b2b9d8c0-da6b-4eff-accf-b8f5393c0def",
      "name": "Filter"
    },
    {
      "parameters": {
        "maxItems": 5
      },
      "type": "n8n-nodes-base.limit",
      "typeVersion": 1,
      "position": [
        7424,
        1904
      ],
      "id": "4e219f0b-8c38-4a4c-8e96-556c82d35ff9",
      "name": "Limit"
    },
    {
      "parameters": {
        "aggregate": "aggregateAllItemData",
        "options": {}
      },
      "type": "n8n-nodes-base.aggregate",
      "typeVersion": 1,
      "position": [
        7632,
        1904
      ],
      "id": "a59bd01c-3636-4092-9295-154c55f0333f",
      "name": "Aggregate"
    },
    {
      "parameters": {
        "collection": "users",
        "options": {},
        "query": "{ \"consent\": true }"
      },
      "type": "n8n-nodes-base.mongoDb",
      "typeVersion": 1.3,
      "position": [
        7840,
        1904
      ],
      "id": "d3438d8c-96b1-439f-a4be-011ecb9f4f95",
      "name": "Find documents",
      "credentials": {
        "mongoDb": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "c1",
              "leftValue": "={{ Number($json.sendHour) }}",
              "rightValue": "={{ $now.hour }}",
              "operator": {
                "type": "number",
                "operation": "equals"
              }
            },
            {
              "id": "c2",
              "leftValue": "={{ String($json.consent).toLowerCase() === 'true' }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.filter",
      "typeVersion": 2.3,
      "position": [
        8048,
        1904
      ],
      "id": "06789a2c-f542-41ae-9293-2a8b8a068579",
      "name": "Filter1"
    },
    {
      "parameters": {
        "promptType": "=define",
        "text": "=Tu es un curateur de veille climatique. Le lecteur s'int\u00e9resse \u00e0 : {{ $json.interests }}\n\nVoici les articles du jour au format JSON :\n{{ JSON.stringify($('Aggregate').first().json.data) }}\n\nS\u00e9lectionne les 5 articles les plus pertinents pour ce lecteur.\n\nR\u00e9ponds UNIQUEMENT avec un tableau JSON valide, sans texte avant ou apr\u00e8s, sans balises markdown, au format exact :\n[{\"title\": \"titre de l'article\", \"link\": \"url exacte fournie\", \"summary\": \"r\u00e9sum\u00e9 en une phrase courte (20 mots maximum)\"}]\n\nImportant : recopie les liens exactement tels qu'ils sont fournis, ne les modifie jamais. N'invente aucun article.",
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.9,
      "position": [
        8256,
        1904
      ],
      "id": "0b5fc6d6-30e4-42f3-8801-465b3349abd4",
      "name": "Basic LLM Chain"
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "meta-llama/llama-4-scout-17b-16e-instruct",
          "mode": "list",
          "cachedResultName": "meta-llama/llama-4-scout-17b-16e-instruct"
        },
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        8256,
        2112
      ],
      "id": "c72f8a26-2922-47c7-8d12-1ef532b43b92",
      "name": "OpenAI Chat Model",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const users = $('Filter1').all();\nconst results = [];\nlet i = 0;\n\nfor (const item of $input.all()) {\n  const raw = item.json.text || \"\";\n  let clean = raw.replace(/```json/g, \"\").replace(/```/g, \"\").trim();\n\n  const start = clean.indexOf(\"[\");\n  const end = clean.lastIndexOf(\"]\");\n  if (start !== -1 && end !== -1 && end > start) {\n    clean = clean.slice(start, end + 1);\n  } else if (start !== -1) {\n    clean = clean.slice(start);\n  }\n\n  let articles = null;\n  try {\n    articles = JSON.parse(clean);\n  } catch (e) {\n    const lastBrace = clean.lastIndexOf(\"}\");\n    if (lastBrace !== -1) {\n      try {\n        articles = JSON.parse(clean.slice(0, lastBrace + 1) + \"]\");\n      } catch (e2) {\n        articles = null;\n      }\n    }\n  }\n\n  if (!articles || !Array.isArray(articles) || articles.length === 0) {\n    i++;\n    continue;\n  }\n\n  const articlesHtml = articles.map(a =>\n    \"<div style='margin-bottom:20px'>\"\n    + \"<h3 style='margin-bottom:4px'>\" + (a.title || \"\") + \"</h3>\"\n    + \"<p style='margin:4px 0'>\" + (a.summary || \"\") + \"</p>\"\n    + \"<a href='\" + (a.link || \"#\") + \"'>Lire l'article</a>\"\n    + \"</div>\"\n  ).join(\"\");\n\n  const html = \"<h1>Votre veille climat du jour</h1>\"\n    + articlesHtml\n    + \"<hr>\"\n    + \"<p style='color:gray;font-size:12px'>Vous recevez cet email car vous \u00eates inscrit \u00e0 Persona. \"\n    + \"<a href='http://localhost:5678/form/1064885f-7eb2-4636-b9bb-e6bd6ccedc55'>Cliquez ici pour vous d\u00e9sabonner</a>.</p>\";\n\n  results.push({\n    json: {\n      html: html,\n      email: users[i] ? users[i].json.email : undefined\n    }\n  });\n\n  i++;\n}\n\nreturn results;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        8576,
        1904
      ],
      "id": "3ca188a1-831e-4fe1-8d82-b7d1d9a31827",
      "name": "Code in JavaScript"
    },
    {
      "parameters": {
        "sendTo": "={{ $json.email }}",
        "subject": "=Persona \u00b7 Votre veille du {{ $now.format('dd/MM') }}",
        "message": "={{ $json.html }}",
        "options": {}
      },
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.2,
      "position": [
        8784,
        1904
      ],
      "id": "ab93eda9-18c1-4261-857e-3e9d5d8b0287",
      "name": "Send a message",
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "typeVersion": 1.4,
      "position": [
        5760,
        2384
      ],
      "id": "94fa69e2-7229-433a-93ad-5befc1cdf30d",
      "name": "When chat message received"
    },
    {
      "parameters": {
        "options": {
          "systemMessage": "Tu es Persona, un assistant d'inscription \u00e0 une newsletter personnalis\u00e9e.\nTa mission : collecter dans la conversation, dans l'ordre :\n1. le pr\u00e9nom de l'utilisateur\n2. son adresse e-mail\n3. ses centres d'int\u00e9r\u00eat dans le domaine du climat et de l'environnement (par exemple : \u00e9nergies renouvelables, politique climatique, biodiversit\u00e9, transition \u00e9nerg\u00e9tique, agriculture durable)\n4. l'heure \u00e0 laquelle il veut recevoir la newsletter (0-23)\n5. son consentement explicite pour stocker son e-mail (oui/non)\n\nQuand tu as TOUTES ces informations et que le consentement est oui,\nappelle l'outil save_user en transmettant name, email, interests, sendHour et consent.\nPour le champ consent, envoie exactement TRUE, jamais \"oui\".\nNe sauvegarde jamais sans consentement explicite.\nR\u00e9ponds toujours en fran\u00e7ais, bref et amical.\n\nApr\u00e8s avoir sauvegard\u00e9 avec succ\u00e8s, confirme \u00e0 l'utilisateur et informe-le\nen une phrase : il peut se d\u00e9sinscrire \u00e0 tout moment via le lien pr\u00e9sent\ndans chaque newsletter, et ses donn\u00e9es seront alors supprim\u00e9es.\n\nIMPORTANT : pour sauvegarder, tu dois APPELER l'outil save_user via le\nm\u00e9canisme d'appel d'outil. Ne mentionne JAMAIS l'outil, son nom, ni le fait\nque tu vas l'appeler, dans aucune de tes r\u00e9ponses \u00e0 l'utilisateur. Pas de\nJSON, pas de code, pas de note technique, pas de parenth\u00e8se explicative.\nL'utilisateur ne doit jamais savoir qu'un outil existe.\n\n\nYou must use all available tool if relevant : \n\n- Persona save user"
        }
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3.1,
      "position": [
        5968,
        2384
      ],
      "id": "50faabf2-b7d9-45fc-9699-5e120398a552",
      "name": "AI Agent"
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "llama-3.3-70b-versatile",
          "mode": "list",
          "cachedResultName": "llama-3.3-70b-versatile"
        },
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        5840,
        2592
      ],
      "id": "39ec5c1e-a274-4ac2-a63f-b27b14b91685",
      "name": "OpenAI Chat Model1",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {},
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "typeVersion": 1.4,
      "position": [
        6016,
        2608
      ],
      "id": "7e2c58e6-6310-4003-a6b8-64fe57729ea6",
      "name": "Simple Memory"
    },
    {
      "parameters": {
        "formTitle": "Se d\u00e9sabonner de Persona",
        "formDescription": "Entrez votre e-mail pour ne plus recevoir la newsletter. Vos donn\u00e9es seront supprim\u00e9es.",
        "formFields": {
          "values": [
            {
              "fieldLabel": "email",
              "fieldType": "email"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.formTrigger",
      "typeVersion": 2.6,
      "position": [
        5728,
        2864
      ],
      "id": "a91a0a6f-c056-4fd0-9613-0cd8e716a194",
      "name": "On form submission"
    },
    {
      "parameters": {
        "operation": "delete",
        "collection": "users",
        "query": "={{ JSON.stringify({ email: $json.email }) }}"
      },
      "type": "n8n-nodes-base.mongoDb",
      "typeVersion": 1.3,
      "position": [
        6048,
        2864
      ],
      "id": "f5224af1-f259-45e9-8807-566fc0bd6c4d",
      "name": "Delete subscriber",
      "credentials": {
        "mongoDb": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "description": "Enregistre un nouvel abonn\u00e9 \u00e0 la newsletter. Appelle cet outil avec name, email, interests, sendHour et consent (TRUE) quand toutes les informations sont collect\u00e9es et que le consentement est donn\u00e9.",
        "workflowId": {
          "__rl": true,
          "value": "18Y8CYJkMJVMBh7r",
          "mode": "list",
          "cachedResultUrl": "/workflow/18Y8CYJkMJVMBh7r",
          "cachedResultName": "Persona Save User"
        },
        "workflowInputs": {
          "mappingMode": "defineBelow",
          "value": {
            "consent": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('consent', ``, 'boolean') }}",
            "sendHour": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('sendHour', ``, 'number') }}",
            "name": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('name', ``, 'string') }}",
            "email": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('email', ``, 'string') }}",
            "interests": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('interests', ``, 'string') }}"
          },
          "matchingColumns": [],
          "schema": [
            {
              "id": "name",
              "displayName": "name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "string",
              "removed": false
            },
            {
              "id": "email",
              "displayName": "email",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "string",
              "removed": false
            },
            {
              "id": "interests",
              "displayName": "interests",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "string",
              "removed": false
            },
            {
              "id": "sendHour",
              "displayName": "sendHour",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "number",
              "removed": false
            },
            {
              "id": "consent",
              "displayName": "consent",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "boolean",
              "removed": false
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        }
      },
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "typeVersion": 2.2,
      "position": [
        6240,
        2592
      ],
      "id": "8b1ce746-d4c1-4170-b3dc-cb22623412d3",
      "name": "Call 'Persona Save User'"
    }
  ],
  "connections": {
    "When clicking Execute workflow": {
      "main": [
        [
          {
            "node": "RSS Read",
            "type": "main",
            "index": 0
          },
          {
            "node": "RSS Read1",
            "type": "main",
            "index": 0
          },
          {
            "node": "RSS Read2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "RSS Read",
            "type": "main",
            "index": 0
          },
          {
            "node": "RSS Read1",
            "type": "main",
            "index": 0
          },
          {
            "node": "RSS Read2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "RSS Read": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "RSS Read1": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "RSS Read2": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 2
          }
        ]
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields": {
      "main": [
        [
          {
            "node": "Remove Duplicates",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Remove Duplicates": {
      "main": [
        [
          {
            "node": "Filter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter": {
      "main": [
        [
          {
            "node": "Limit",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Limit": {
      "main": [
        [
          {
            "node": "Aggregate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate": {
      "main": [
        [
          {
            "node": "Find documents",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Find documents": {
      "main": [
        [
          {
            "node": "Filter1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter1": {
      "main": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Basic LLM Chain": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Send a message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When chat message received": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Simple Memory": {
      "ai_memory": [
        [
          {
            "node": "AI Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "On form submission": {
      "main": [
        [
          {
            "node": "Delete subscriber",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call 'Persona Save User'": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    }
  },
  "meta": {
    "templateCredsSetupCompleted": true
  }
}