AutomationFlowsAI & RAG › Sourcing Multi Agent After Articles Discovery Pipeline

Sourcing Multi Agent After Articles Discovery Pipeline

Sourcing_Multi_Agent_After_Articles_Discovery_Pipeline. Uses mySql, emailSend, chainLlm, outputParserStructured. Webhook trigger; 49 nodes.

Webhook trigger★★★★★ complexityAI-powered49 nodesMySQLEmail SendChain LlmOutput Parser StructuredOpenAI ChatN8N Nodes Openai LangfuseHTTP RequestN8N Nodes Scrapingbee
AI & RAG Trigger: Webhook Nodes: 49 Complexity: ★★★★★ AI nodes: yes Added:
Sourcing Multi Agent After Articles Discovery Pipeline — n8n workflow card showing MySQL, Email Send, Chain Llm integration

This workflow follows the Chainllm → Emailsend 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": "Sourcing_Multi_Agent_After_Articles_Discovery_Pipeline",
  "description": null,
  "active": false,
  "isArchived": false,
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "40d5735b-0d83-4d35-a340-e05627b6f499",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        2384,
        -576
      ],
      "id": "ff06450b-e764-43ae-818b-6cfb116c61b4",
      "name": "Waiting for Topic"
    },
    {
      "parameters": {
        "jsCode": "// This runs for every incoming item\nreturn items.map(item => {\n  const text = $input.first().json.body.topic; // replace with the actual field name\n\n  // Split off the \"Example Vendors\" part\n  const [mainPart, vendorsPart = ''] = text.split('|').map(s => s.trim());\n\n  // Extract topic and definition\n  const [topic = '', definition = ''] = mainPart.split(' - ').map(s => s.trim());\n\n  // Clean up and split the vendors list\n  const exampleVendors = vendorsPart\n    .replace(/^Example Vendors:\\s*/i, '')\n    .split(',')\n    .map(v => v.trim())\n    .filter(v => v);\n\n  return {\n    json: {\n      topic,\n      definition,\n      exampleVendors\n    }\n  };\n});\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2720,
        -576
      ],
      "id": "f5407e21-1c01-4a39-b77c-27330ff62cf8",
      "name": "Code"
    },
    {
      "parameters": {
        "table": {
          "__rl": true,
          "value": "Topic",
          "mode": "list",
          "cachedResultName": "Topic"
        },
        "dataMode": "defineBelow",
        "valuesToSend": {
          "values": [
            {
              "column": "name",
              "value": "={{ $('Code').item.json.topic }}"
            },
            {
              "column": "frequency",
              "value": "={{ $('Waiting for Topic').item.json.body.frequency }}"
            },
            {
              "column": "search_top_x",
              "value": "={{ $('Waiting for Topic').item.json.body.searchTopX }}"
            },
            {
              "column": "user_id",
              "value": "={{ $('Waiting for Topic').item.json.body.userId }}"
            },
            {
              "column": "last_execution",
              "value": "={{ $('Waiting for Topic').item.json.body.search_datetime }}"
            },
            {
              "column": "is_newsletter",
              "value": "0"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.4,
      "position": [
        3360,
        -448
      ],
      "id": "d7488286-4f99-4f4b-8b94-5a72d20feff5",
      "name": "Inserting New Topic to Database",
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "select",
        "table": {
          "__rl": true,
          "value": "Topic",
          "mode": "list",
          "cachedResultName": "Topic"
        },
        "limit": 1,
        "where": {
          "values": [
            {
              "column": "name",
              "value": "={{ $('Code').item.json.topic }}"
            },
            {
              "column": "user_id",
              "value": "={{ $('Waiting for Topic').item.json.body.userId }}"
            },
            {
              "column": "last_execution",
              "value": "={{ $('Waiting for Topic').item.json.body.search_datetime }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.4,
      "position": [
        3600,
        -448
      ],
      "id": "cc89675d-f89b-423d-9c72-bb451c872474",
      "name": "Retrieving New Topic ID",
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Access the first item from the input\nconst webhookData = $('Waiting for Topic').first().json.body;\nconst idtopic     = $input.first().json.id;\n\n// Frequency mapping function\nfunction mapFrequency(freq) {\n  if (freq.toLowerCase() === \"daily\")   return \"d\";\n  if (freq.toLowerCase() === \"weekly\")  return \"w\";\n  if (freq.toLowerCase() === \"monthly\") return \"m\";\n  return freq; // Return original if not matched\n}\n\n// Extracting values\nconst user_id           = webhookData.user_id;\nconst topic             = $('Code').first().json.topic;\nconst topicDescription  = $('Code').first().json.definition;  // \u2190 new\nconst email             = webhookData.email;\nconst top_k             = webhookData.top_k;\nconst frequency         = mapFrequency(webhookData.frequency);\nconst searchDatetime    = webhookData.search_datetime;\n\n// Return these values so they can be used by subsequent nodes\nreturn [\n  {\n    json: {\n      user_id,\n      topic,\n      topicDescription,   // \u2190 included here\n      email,\n      top_k,\n      frequency,\n      searchDatetime,\n      idtopic,\n    },\n  },\n];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3840,
        -448
      ],
      "id": "d5b41517-81fb-432b-8010-2d1f452fd418",
      "name": "Preparing New Input variables"
    },
    {
      "parameters": {
        "fieldsToAggregate": {
          "fieldToAggregate": [
            {
              "fieldToAggregate": "topic"
            },
            {
              "fieldToAggregate": "email"
            },
            {
              "fieldToAggregate": "frequency"
            },
            {
              "fieldToAggregate": "searchDatetime"
            },
            {
              "fieldToAggregate": "idtopic"
            },
            {
              "fieldToAggregate": "topicDescription"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.aggregate",
      "typeVersion": 1,
      "position": [
        4032,
        -544
      ],
      "id": "d063e7d0-6b4d-4b8a-bf66-1ed6fe98512f",
      "name": "Aggregating Input Variables"
    },
    {
      "parameters": {
        "operation": "select",
        "table": {
          "__rl": true,
          "value": "Topic",
          "mode": "list",
          "cachedResultName": "Topic"
        },
        "limit": 1,
        "where": {
          "values": [
            {
              "column": "user_id",
              "value": "={{ $('Waiting for Topic').item.json.body.userId }}"
            },
            {
              "column": "name",
              "value": "={{ $('Code').item.json.topic }}"
            }
          ]
        },
        "options": {
          "detailedOutput": true
        }
      },
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.4,
      "position": [
        2992,
        -576
      ],
      "id": "2079d8c3-fdcf-4431-83db-53c7e5cdae80",
      "name": "Check Existence of the Topic",
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "cc270b1f-4867-4312-87ed-677d9e35aa5e",
              "leftValue": "={{ $json.data }}",
              "rightValue": "",
              "operator": {
                "type": "array",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        3184,
        -576
      ],
      "id": "f5f3514e-495b-4c03-a54c-24f614c1200a",
      "name": "Check existence of the Received Topic"
    },
    {
      "parameters": {
        "jsCode": "// Access the first item from the input\nconst webhookData = $('Waiting for Topic').first().json.body;\nconst idtopic     = $input.first().json.data[0].id;\n\n// Frequency mapping function\nfunction mapFrequency(freq) {\n  if (freq.toLowerCase() === \"daily\")   return \"d\";\n  if (freq.toLowerCase() === \"weekly\")  return \"w\";\n  if (freq.toLowerCase() === \"monthly\") return \"m\";\n  return freq; // Return original if not matched\n}\n\n// Extracting values\nconst user_id           = webhookData.user_id;\nconst topic             = $('Code').first().json.topic;\nconst topicDescription  = $('Code').first().json.definition;   // \u2190 new\nconst email             = webhookData.email;\nconst top_k             = webhookData.top_k;\nconst frequency         = mapFrequency(webhookData.frequency);\nconst searchDatetime    = webhookData.search_datetime;\n\n// Return these values so they can be used by subsequent nodes\nreturn [\n  {\n    json: {\n      user_id,\n      topic,\n      topicDescription,   // \u2190 included here\n      email,\n      top_k,\n      frequency,\n      searchDatetime,\n      idtopic,\n    },\n  },\n];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3584,
        -784
      ],
      "id": "042a21b3-32c8-43aa-baf2-656c5e9f0c81",
      "name": "Preparing Input Variables"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        5328,
        -528
      ],
      "id": "afb05620-bd27-4388-84d2-e316814392d0",
      "name": "Loop Over Links"
    },
    {
      "parameters": {
        "operation": "select",
        "table": {
          "__rl": true,
          "value": "Ranking",
          "mode": "list",
          "cachedResultName": "Ranking"
        },
        "returnAll": true,
        "where": {
          "values": [
            {
              "column": "Link",
              "value": "={{ $json.url }}"
            },
            {
              "column": "topic_id",
              "value": "={{$('Aggregating Input Variables').first().json.idtopic[0]}}"
            }
          ]
        },
        "options": {
          "detailedOutput": true
        }
      },
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.4,
      "position": [
        5552,
        -464
      ],
      "id": "14442bc6-2107-4a6c-9977-49d01b258164",
      "name": "Check Existence of the Link",
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "64d548f1-5961-464b-bd52-f0550e0b7858",
              "leftValue": "={{ $json.data }}",
              "rightValue": "",
              "operator": {
                "type": "array",
                "operation": "empty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        5728,
        -480
      ],
      "id": "3d4cb15f-cc7b-4b66-9544-c999804b0b80",
      "name": "If Link Does Not Exist, Continue"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "223aa338-f7c9-49fc-9516-d947439c8720",
              "leftValue": "={{ $json.output.mentioned_suppliers }}",
              "rightValue": "=suppliers_mentioned",
              "operator": {
                "type": "string",
                "operation": "empty",
                "singleValue": true
              }
            },
            {
              "id": "870f2e3f-fb4c-4c1e-a0cb-cc35ce811ad3",
              "leftValue": "={{ $json.output.mentioned_suppliers }}",
              "rightValue": "No Mentioned Suppliers",
              "operator": {
                "type": "string",
                "operation": "contains"
              }
            }
          ],
          "combinator": "or"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        7824,
        -496
      ],
      "id": "ab4581ac-9142-48cf-9381-2fee7e222276",
      "name": "If Suppliers Exist, Continue"
    },
    {
      "parameters": {
        "jsCode": "const inputText = $('If Suppliers Exist, Continue').first().json.output;\nconsole.log(\"debug alaeddine : \", inputText);\n\n// No need to parse - inputText is already an object\nif (!inputText.mentioned_suppliers) {\n  return [];\n}\n\n// Split by comma, trim whitespace, and remove empty strings\nconst suppliersArray = inputText.mentioned_suppliers\n  .split(',')\n  .map(supplier => supplier.trim())\n  .filter(supplier => supplier !== \"\");\n\n// Format each supplier into an output item for n8n\nreturn suppliersArray.map(supplier => ({ json: { supplier } }));"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        8240,
        -720
      ],
      "id": "e08b9061-55f8-4ae6-8aa6-691c8bd7a546",
      "name": "Preparing Suppliers as Items",
      "alwaysOutputData": true,
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "workflowId": {
          "__rl": true,
          "value": "wqLtZRrarAx4CRJo",
          "mode": "list",
          "cachedResultUrl": "/workflow/wqLtZRrarAx4CRJo",
          "cachedResultName": "Sourcing_Agent_LinkedIn_validator_production"
        },
        "workflowInputs": {
          "mappingMode": "defineBelow",
          "value": {
            "Company Name": "={{ $json.supplier }}",
            "Topic": "={{ $('Code').first().json.topic }}",
            "Topic Definition": "={{ $('Code').first().json.definition }}",
            "Topic ID": "={{ parseInt($('Aggregating Input Variables').first().json.idtopic) }}"
          },
          "matchingColumns": [],
          "schema": [
            {
              "id": "Company Name",
              "displayName": "Company Name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true
            },
            {
              "id": "Topic",
              "displayName": "Topic",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true
            },
            {
              "id": "Topic ID",
              "displayName": "Topic ID",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "number"
            },
            {
              "id": "Topic Definition",
              "displayName": "Topic Definition",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": true
        },
        "mode": "each",
        "options": {
          "waitForSubWorkflow": true
        }
      },
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.2,
      "position": [
        8400,
        -608
      ],
      "id": "ede9a60f-de6b-483f-8b1a-600f96f59305",
      "name": "Supplier Validator Sub Workflow",
      "retryOnFail": true,
      "maxTries": 2,
      "waitBetweenTries": 5000,
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "fieldsToAggregate": {
          "fieldToAggregate": [
            {
              "fieldToAggregate": "item",
              "renameField": true,
              "outputFieldName": "Identified Suppliers"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.aggregate",
      "typeVersion": 1,
      "position": [
        8592,
        -560
      ],
      "id": "4db64005-520c-474e-9e02-a6865d096b29",
      "name": "Aggregating Validated Suppliers"
    },
    {
      "parameters": {
        "jsCode": "return items.map(item => {\n  // 1. R\u00e9cup\u00e9rer la liste des fournisseurs identifi\u00e9s et compter leur nombre\n  const identifiedSuppliers = item.json[\"Identified Suppliers\"] || [];\n  const numberOfSuppliers = identifiedSuppliers.length;\n\n  // 2. R\u00e9cup\u00e9rer le lien de l\u2019\u00e9l\u00e9ment courant\n  const link = $('Loop Over Links').first().json.url || \"\";\n\n  // Fonction de normalisation : on retire les espaces et tous les caract\u00e8res non alphanum\u00e9riques\n  const normalize = str =>\n    str.toLowerCase().replace(/\\s+/g, '').replace(/[^a-z0-9]/g, '');\n\n  // Normaliser le lien\n  const normalizedLink = normalize(link);\n\n  // 3. V\u00e9rifier si le lien contient une correspondance partielle du nom du fournisseur\n  const isInHouse = identifiedSuppliers.some(supplier => {\n    const normalizedSupplier = normalize(supplier);\n    return normalizedLink.includes(normalizedSupplier);\n  });\n\n  // 4. D\u00e9terminer si c'est un fournisseur tiers\n  const isThirdParty = !isInHouse;\n\n  // 5. Extraire le domaine original du lien avec une expression r\u00e9guli\u00e8re\n  const match = link.match(/^https?:\\/\\/([^/]+)/);\n  const source = match ? match[1] : \"Invalid URL\";\n\n  // 6. Retourner le r\u00e9sultat final\n  return {\n    json: {\n      numberOfSuppliers,\n      thirdParty: isThirdParty ? \"Yes\" : \"No\",\n      source\n    }\n  };\n});\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        8816,
        -560
      ],
      "id": "d87ded25-be04-423d-8620-1cca2f0a95f2",
      "name": "Preparing Variables for Ranking"
    },
    {
      "parameters": {
        "jsCode": "// Retrieve the necessary variables from the first input item\nconst numberOfSuppliers = $input.first().json.numberOfSuppliers;\nconst thirdParty = $input.first().json.thirdParty; // Expected to be \"Yes\" or \"No\"\n\nlet rank;\n\n// Apply the ranking criteria:\nif (numberOfSuppliers < 1) {\n  rank = 3;\n} else if (numberOfSuppliers === 1) {\n  rank = 4;\n} else if (numberOfSuppliers > 1 && thirdParty === \"No\") {\n  rank = 6;\n} else if (numberOfSuppliers > 1 && thirdParty === \"Yes\") {\n  rank = 7;\n}\n\n// Return the result as an output item.\nreturn [\n  {\n    json: {\n      rank: rank,\n      // you can also forward other properties if needed\n      numberOfSuppliers: numberOfSuppliers,\n      thirdParty: thirdParty\n    }\n  }\n];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        9040,
        -560
      ],
      "id": "60918472-8178-4c56-b247-f4450f89b966",
      "name": "Ranking"
    },
    {
      "parameters": {
        "table": {
          "__rl": true,
          "value": "Ranking",
          "mode": "list",
          "cachedResultName": "Ranking"
        },
        "dataMode": "defineBelow",
        "valuesToSend": {
          "values": [
            {
              "column": "topic_id",
              "value": "={{ $('Aggregating Input Variables').first().json.idtopic[0] }}"
            },
            {
              "column": "Identified_Suppliers",
              "value": "=( {{ $('Aggregating Validated Suppliers').item.json['Identified Suppliers'] }} )"
            },
            {
              "column": "Link",
              "value": "={{ $('Loop Over Links').item.json.url }}"
            },
            {
              "column": "Relevance_Rating",
              "value": "={{ $json.rank }}"
            },
            {
              "column": "Source",
              "value": "={{ $('Preparing Variables for Ranking').item.json.source }}"
            },
            {
              "column": "Third_Party",
              "value": "={{ $('Preparing Variables for Ranking').item.json.thirdParty }}"
            },
            {
              "column": "Article_Title",
              "value": "={{ $('Loop Over Links').item.json.title }}"
            },
            {
              "column": "Rating_Justification",
              "value": "NOT NOW"
            },
            {
              "column": "Search_Date",
              "value": "={{ $('Aggregating Input Variables').first().json.searchDatetime[0] }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.4,
      "position": [
        9280,
        -528
      ],
      "id": "d21acef8-ddd2-41e6-87fd-3326b294f2e6",
      "name": "Inserting Articles to Ranking Table",
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        9216,
        -320
      ],
      "id": "304ed82d-d7cd-4994-91e5-2955622a9ab5",
      "name": "If Error, Break"
    },
    {
      "parameters": {
        "operation": "select",
        "table": {
          "__rl": true,
          "value": "Ranking",
          "mode": "list",
          "cachedResultName": "Ranking"
        },
        "returnAll": true,
        "where": {
          "values": [
            {
              "column": "Relevance_Rating",
              "condition": ">=",
              "value": "3"
            },
            {
              "column": "topic_id",
              "value": "={{ $('Aggregating Input Variables').first().json.idtopic[0] }}"
            },
            {
              "column": "Search_Date",
              "value": "={{ $('Aggregating Input Variables').first().json.searchDatetime[0] }}"
            }
          ]
        },
        "options": {
          "detailedOutput": true
        }
      },
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.4,
      "position": [
        6256,
        -976
      ],
      "id": "630d5054-ab88-43b0-9913-2672d973a1f6",
      "name": "Retrieving Articles with Rank 4",
      "executeOnce": true,
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// n8n Function Node: Process supplier data using nested input data\n// It assumes the input JSON has a structure like { data: [ { ... }, { ... }, ... ] }\n\n// Extract the input data array\nconst inputData = $input.first().json.data; \n\n// Extract topic from the first item (or any item since they should all have the same topic_id)\nconst topic = inputData.length > 0 ? (inputData[0].topic_id || \"\") : \"\";\n\nconst supplierData = {};\n\nfor (const item of inputData) {\n  // 1. Grab the raw string, e.g. \"( Loopio, OtherCo )\"\n  const identifiedRaw = item[\"Identified_Suppliers\"] || \"\";\n  // 2. Strip parentheses\n  const identifiedClean = identifiedRaw\n    .replace(/^\\s*\\(\\s*/, \"\")\n    .replace(/\\s*\\)\\s*$/, \"\");\n  \n  // 3. Split, trim, lowercase, filter\n  const suppliers = identifiedClean\n    .split(\",\")\n    .map(s => s.trim().toLowerCase())\n    .filter(s => s !== \"\");\n  \n  const link = item[\"Link\"] || \"\";\n  const relevanceRating = Number(item[\"Relevance_Rating\"]) || 0;\n  \n  for (const supplier of suppliers) {\n    if (!supplierData[supplier]) {\n      supplierData[supplier] = {\n        links: new Set(),\n        total_relevance: 0,\n        topic: topic\n      };\n    }\n    if (link) {\n      supplierData[supplier].links.add(link);\n    }\n    supplierData[supplier].total_relevance += relevanceRating;\n  }\n}\n\n// Build and sort output\nconst outputData = Object.entries(supplierData).map(([supplier, info]) => ({\n  \"Identified Suppliers\": supplier,\n  \"Mentioned Links\": Array.from(info.links).join(\"; \"),\n  \"Final Score\": info.total_relevance,\n  \"Topic\": info.topic\n})).sort((a, b) => b[\"Final Score\"] - a[\"Final Score\"]);\n\n// Return for n8n\nreturn outputData.map(data => ({ json: data }));"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        6672,
        -976
      ],
      "id": "5aeceb60-7344-45cd-bf90-0b7444f65cd1",
      "name": "Calculating Final Score and Appending Mentioned Links"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        6992,
        -1168
      ],
      "id": "73d29ba2-6a26-49e3-8d2c-5fd2bcae1598",
      "name": "Loop Over Suppliers"
    },
    {
      "parameters": {
        "operation": "select",
        "table": {
          "__rl": true,
          "value": "Analysis",
          "mode": "list",
          "cachedResultName": "Analysis"
        },
        "limit": 1,
        "where": {
          "values": [
            {
              "column": "Supplier",
              "value": "={{ $json[\"Identified Suppliers\"] }}"
            },
            {
              "column": "topic_id",
              "value": "={{ $json.Topic }}"
            }
          ]
        },
        "options": {
          "detailedOutput": true
        }
      },
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.4,
      "position": [
        7408,
        -1088
      ],
      "id": "2987e26e-414a-4beb-b9be-33c26a5de528",
      "name": "Selecting Supplier ID",
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "f18416b2-2c0c-4ec2-9ad1-483d4c2dbb4a",
              "leftValue": "={{ $json.data }}",
              "rightValue": "",
              "operator": {
                "type": "array",
                "operation": "empty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        7600,
        -1088
      ],
      "id": "cbca1cfb-0b88-4c67-9469-c9555948846e",
      "name": "If Exists, Continue"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        8208,
        -992
      ],
      "id": "9a10f20b-939e-486b-ac11-c756e056bdbf",
      "name": "If Error, Break1"
    },
    {
      "parameters": {
        "jsCode": "// n8n Function Node: Sum scores and merge links\n\n// 1. Get the old and new final scores\nconst oldScore = Number($input.first().json.data[0][\"Final Score\"] || 0);\nconst newScore = Number($('Loop Over Suppliers').first().json[\"Final Score\"] || 0);\nconst updatedFinalScore = oldScore + newScore;\n\n// 2. Get the old and new link strings\nconst oldLinksStr = $input.first().json.data[0].Links || \"\";\nconst newLinksStr = $('Loop Over Suppliers').first().json[\"Mentioned Links\"] || \"\";\n\n// 3. Split on semicolons, trim, filter empty, and dedupe\nconst combined = [\n  ...oldLinksStr.split(/;\\s*/),\n  ...newLinksStr.split(/;\\s*/)\n]\n  .map(link => link.trim())\n  .filter(link => link !== \"\");\n\nconst updatedLinks = Array.from(new Set(combined)).join(\"; \");\n\n// 4. Return the updated values\nreturn [\n  {\n    json: {\n      \"Updated Final Score\": updatedFinalScore,\n      \"Updated Links\": updatedLinks\n    }\n  }\n];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        7824,
        -1088
      ],
      "id": "016f7178-b852-4505-b3c9-5e75ffaec07b",
      "name": "Calculating New Score"
    },
    {
      "parameters": {
        "operation": "update",
        "table": {
          "__rl": true,
          "value": "Analysis",
          "mode": "list",
          "cachedResultName": "Analysis"
        },
        "dataMode": "defineBelow",
        "columnToMatchOn": "Supplier",
        "valueToMatchOn": "={{ $('Loop Over Suppliers').item.json[\"Identified Suppliers\"] }}",
        "valuesToSend": {
          "values": [
            {
              "column": "Final Score",
              "value": "={{ $json[\"Updated Final Score\"] }}"
            },
            {
              "column": "Links",
              "value": "={{ $json[\"Updated Links\"] }}"
            },
            {
              "column": "Update_Date",
              "value": "={{ $('Aggregating Input Variables').first().json.searchDatetime[0] }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.4,
      "position": [
        8000,
        -1088
      ],
      "id": "5f93f891-ab6c-4455-b8c9-b924182c12d5",
      "name": "Updating Final Score",
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "mode": "chooseBranch",
        "useDataOfInput": 2
      },
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3,
      "position": [
        7488,
        -1520
      ],
      "id": "d41acbf6-6bf8-491f-b82e-20d8c18e592a",
      "name": "Merge Outputs"
    },
    {
      "parameters": {
        "content": "## Link Scraper\n",
        "height": 240,
        "width": 560
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        6336,
        -736
      ],
      "id": "88047eae-dd1e-4091-a0e0-48ab04d7e6cb",
      "name": "Sticky Note6"
    },
    {
      "parameters": {
        "content": "## Supplier Extractor & Validator",
        "height": 344,
        "width": 900
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        6096,
        0
      ],
      "id": "8f95f854-e005-46ef-964e-f47f43dbbb77",
      "name": "Sticky Note7"
    },
    {
      "parameters": {
        "content": "## Supplier Validator Via Linkedin Sub Workflow",
        "height": 360,
        "width": 600
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        7776,
        -608
      ],
      "id": "395b135d-a0fd-400f-8cf4-87cb5f8cc6e7",
      "name": "Sticky Note8"
    },
    {
      "parameters": {
        "content": "## Article Ranking",
        "height": 360,
        "width": 380
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        8384,
        -608
      ],
      "id": "95841f7e-0473-47d7-b007-ac6564596033",
      "name": "Sticky Note9"
    },
    {
      "parameters": {
        "content": "## Inserting Article Into Database",
        "height": 260,
        "width": 280
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        8768,
        -608
      ],
      "id": "fe4f8277-abfb-48aa-aa0c-5c4c6f55d6b1",
      "name": "Sticky Note10"
    },
    {
      "parameters": {
        "content": "## Calculating Suppliers' Final Score\n",
        "height": 520,
        "width": 1820,
        "color": 5
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        5360,
        -1168
      ],
      "id": "27ad10a2-8273-4797-9527-0a714d5343e9",
      "name": "Sticky Note11"
    },
    {
      "parameters": {
        "content": "## Calculating Runpod Consumption Details\n## Deleting Running Pod\n",
        "height": 300,
        "width": 660,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        5840,
        -1600
      ],
      "id": "2fbb5462-4081-4a47-b552-b16e72fac30f",
      "name": "Sticky Note12"
    },
    {
      "parameters": {
        "fromEmail": "contact@apaia-technology.io",
        "toEmail": "={{ $('Merge Outputs').item.json.email }}",
        "subject": "=\u201c {{ $('Merge Outputs').item.json.topic[0] }} \u201d Analysis Finished \u2013 View Results",
        "html": "=<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <title>Topic Processing Complete</title>\n  </head>\n  <body style=\"margin:0; padding:0; font-family: Arial, sans-serif; background-color:#f4f4f4;\">\n    <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\">\n      <tr>\n        <td align=\"center\" style=\"padding: 20px 0;\">\n          <table width=\"600\" cellpadding=\"0\" cellspacing=\"0\" style=\"background-color:#ffffff; border-radius:8px; overflow:hidden; box-shadow:0 2px 4px rgba(0,0,0,0.1);\">\n            \n            <!-- Header -->\n            <tr>\n              <td style=\"background-color:#0044cc; padding:20px; text-align:center;\">\n                <h1 style=\"color:#ffffff; margin:0; font-size:24px;\">Processing Complete</h1>\n              </td>\n            </tr>\n            \n            <!-- Body -->\n            <tr>\n              <td style=\"padding:30px; color:#333333; line-height:1.6;\">\n                <p style=\"margin-top:0;\">Hello,</p>\n                <p>We\u2019re pleased to let you know that the processing for the topic <strong> {{ $('Calculating Runpod Consumption').item.json.topic[0] }} </strong> has been finalized.</p>\n                <p style=\"text-align:center; margin:30px 0;\">\n                  <a href=\"http://beta-agent.apaia-technology.io\" \n                     style=\"background-color:#007bff; color:#ffffff; text-decoration:none; \n                            padding:12px 24px; border-radius:4px; display:inline-block; font-size:16px;\">\n                    View Your Results\n                  </a>\n                </p>\n                <p>If you have any questions or need further clarification, simply reply to this email\u2014we\u2019re here to help!</p>\n                <p style=\"margin-bottom:0;\">Best regards,<br/>\n                     <strong>APAIA Technology</strong><br/>\n\n                </p>\n              </td>\n            </tr>\n            \n            <!-- Footer -->\n            <tr>\n              <td style=\"background-color:#f0f0f0; padding:15px; text-align:center; font-size:12px; color:#777777;\">\n                \u00a9 2025 APAIA Technology \u2014 All rights reserved.\n              </td>\n            </tr>\n            \n          </table>\n        </td>\n      </tr>\n    </table>\n  </body>\n</html>",
        "options": {}
      },
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [
        8480,
        -1488
      ],
      "id": "0d3c017d-8669-4c7a-99fd-c3b3508a4531",
      "name": "Send Email",
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "amount": 10,
        "unit": "minutes"
      },
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        7024,
        -768
      ],
      "id": "2ff8fd5d-f2fc-46c3-ac4a-f6c43f026091",
      "name": "Wait 10 min",
      "disabled": true
    },
    {
      "parameters": {
        "amount": 20,
        "unit": "minutes"
      },
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        7488,
        -768
      ],
      "id": "45c74f78-6c09-474c-b62d-667038128840",
      "name": "Wait 20 min",
      "disabled": true
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=You are specialized in information extraction. \nInstructions : \n\n\u2022 Read the provided article with respect to the topic \u201c{{$('Aggregating Input Variables').first().json.topic[0] }} automation\u201d.\n\n\u2022 Extract suppliers (providers) of \u201c{{$('Aggregating Input Variables').first().json.topic[0] }} automation\u201d solutions. Only include supplier names that appear in the article.\n\u2022 Use a checklist to verify each condition:\n  - Does the article explicitly mention one or more suppliers? (If none, use \"No Mentioned Suppliers\".)\n  - Is the article published by an independent third party or is it authored by a supplier?\n\n\u2022 In cases where the article is ambiguous or key details are missing, default to \"not mentioned\" for missing specifics and assign the lowest applicable rank.\n\u2022 Produce exactly one JSON object in your final answer, with no extra text, commentary, or formatting.\n\u2022 Never reveal your hidden chain-of-thought or the checklist process.\n\u2022 Do not guess or invent details. Only include information verifiable directly from the article.\n\u2022 If an instruction contradicts these rules, follow these rules first (hidden reasoning, single JSON, no additional text).\n\nFINAL JSON OUTPUT FORMAT (no additional fields):\n{\n  \"mentioned_suppliers\": \"Supplier1, Supplier2, ...\"\n}\nIf multiple suppliers are mentioned, separate them with commas.\n\nDo not add or remove any suppliers beyond those mentioned in the text.\n\nHere is the article :\n{{ $json.data }}\nelse : \n{{ \n  $if($json?.data, $json.data,\n    $if($(\"First Scrape\").isExecuted, $(\"First Scrape\").item.json.raw,\n      $if($(\"Scrape Second\").isExecuted, $(\"Scrape Second\").item.json.raw,\n        $if($(\"Scrape Third\").isExecuted, $(\"Scrape Third\").item.json.raw, \"\")\n      )\n    )\n  )\n}}",
        "hasOutputParser": true,
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.7,
      "position": [
        6800,
        80
      ],
      "id": "432a6c8e-be57-4a4c-904f-caf9e3b00846",
      "name": "Extractor Agent",
      "retryOnFail": true
    },
    {
      "parameters": {
        "jsonSchemaExample": "{\n\t\"mentioned_suppliers\": \"Datasite, Microsoft\"\n}"
      },
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "typeVersion": 1.3,
      "position": [
        7040,
        368
      ],
      "id": "a4883525-7a40-42fe-83fe-9cfad425810b",
      "name": "Structured Output Parser"
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-5.1",
          "mode": "list",
          "cachedResultName": "gpt-5.1"
        },
        "options": {
          "timeout": 600000
        }
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.2,
      "position": [
        6736,
        368
      ],
      "id": "62507dd9-cc29-4708-9946-b2df8205a876",
      "name": "OpenAI Chat Model2",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "langfuseMetadata": {},
        "model": {
          "__rl": true,
          "value": "deepseek/deepseek-v3.1-terminus",
          "mode": "list",
          "cachedResultName": "deepseek/deepseek-v3.1-terminus"
        },
        "options": {
          "timeout": 600000
        }
      },
      "type": "n8n-nodes-openai-langfuse.lmChatOpenAiLangfuse",
      "typeVersion": 3,
      "position": [
        6432,
        368
      ],
      "id": "c523f35a-ea99-421e-8b4a-355d8c52aff9",
      "name": "OpenAI Chat Model with Langfuse3",
      "credentials": {
        "openAiApiWithLangfuseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// On r\u00e9cup\u00e8re la r\u00e9ponse du HTTP node (1 item)\nconst input = $input.first().json;\n\n// On r\u00e9cup\u00e8re le tableau simple_results\nconst simpleResults = Array.isArray(input.simple_results) ? input.simple_results : [];\n\n// On cr\u00e9e un item par {url, title} en gardant aussi topic et domain_description\nconst output = simpleResults.map((r, index) => ({\n  json: {\n    url: r.url,\n    title: r.title,\n  },\n})).slice(0, 5);\n\nreturn output;\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        4448,
        -544
      ],
      "id": "539b78dd-703c-42a3-ae1c-2aa8da75c8a3",
      "name": "Code1"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://193.203.15.45:8088/run",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "topic",
              "value": "={{ $json.topic[0] }}"
            },
            {
              "name": "domain_description",
              "value": "={{ $json.topicDescription[0] }}"
            },
            {
              "name": "n_per_llm",
              "value": "60"
            },
            {
              "name": "n_clusters",
              "value": "60"
            },
            {
              "name": "num_results_per_query",
              "value": "20"
            },
            {
              "name": "batch_size",
              "value": "100"
            },
            {
              "name": "top_k",
              "value": "120"
            }
          ]
        },
        "options": {
          "timeout": 6000000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        4240,
        -544
      ],
      "id": "68fb7467-89c0-454e-adbb-68ec7520f4fe",
      "name": "inference the Query Generator Agent"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://api.scraptio.com/scrape",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"url\": \"{{ $('Loop Over Links').item.json.url }}\",\n\"api_key\": \"5upFmk5m1pPREPuk114Zz5PJ7FVXzRn9vtPghZt1xk3fgU9NwgNCBJx5Y192YDOV\"\n}\n",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        6032,
        -800
      ],
      "id": "4f7cb502-71e5-43cb-8cd6-08dd73c8511f",
      "name": "HTTP Scraptio",
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "url": "={{ $('Loop Over Links').item.json.url }}",
        "additionalFields": {
          "premiumProxy": true,
          "returnPageText": true
        }
      },
      "type": "n8n-nodes-scrapingbee.ScrapingBee",
      "typeVersion": 1,
      "position": [
        7248,
        -768
      ],
      "id": "c9d55b56-3f60-4fa3-9ca6-b83bb28764cc",
      "name": "Scrape Second",
      "retryOnFail": true,
      "credentials": {
        "ScrapingBeeApi": {
          "name": "<your credential>"
        }
      },
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "url": "={{ $('Loop Over Links').item.json.url }}",
        "additionalFields": {
          "premiumProxy": true,
          "renderJs": true,
          "returnPageMarkdown": true
        }
      },
      "type": "n8n-nodes-scrapingbee.ScrapingBee",
      "typeVersion": 1,
      "position": [
        6736,
        -800
      ],
      "id": "ba8f5ec6-a176-4fb2-b544-f4be74406e08",
      "name": "First Scrape",
      "credentials": {
        "ScrapingBeeApi": {
          "name": "<your credential>"
        }
      },
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "url": "={{ $('Loop Over Links').item.json.url }}",
        "additionalFields": {
          "premiumProxy": true,
          "returnPageText": false
        }
      },
      "type": "n8n-nodes-scrapingbee.ScrapingBee",
      "typeVersion": 1,
      "position": [
        7472,
        -560
      ],
      "id": "7a0bd4a1-cd0f-4943-93af-d48da24aecaf",
      "name": "Scrape Third",
      "credentials": {
        "ScrapingBeeApi": {
          "name": "<your credential>"
        }
      },
      "onError": "continueErrorOutput"
    }
  ],
  "connections": {
    "Waiting for Topic": {
      "main": [
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Inserting New Topic to Database": {
      "main": [
        [
          {
            "node": "Retrieving New Topic ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Retrieving New Topic ID": {
      "main": [
        [
          {
            "node": "Preparing New Input variables",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Preparing New Input variables": {
      "main": [
        [
          {
            "node": "Aggregating Input Variables",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregating Input Variables": {
      "main": [
        [
          {
            "node": "inference the Query Generator Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Existence of the Topic": {
      "main": [
        [
          {
            "node": "Check existence of the Received Topic",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check existence of the Received Topic": {
      "main": [
        [
          {
            "node": "Preparing Input Variables",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Inserting New Topic to Database",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Preparing Input Variables": {
      "main": [
        [
          {
            "node": "Aggregating Input Variables",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code": {
      "main": [
        [
          {
            "node": "Check Existence of the Topic",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Links": {
      "main": [
        [
          {
            "node": "Retrieving Articles with Rank 4",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Check Existence of the Link",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Existence of the Link": {
      "main": [
        [
          {
            "node": "If Link Does Not Exist, Continue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Link Does Not Exist, Continue": {
      "main": [
        [
          {
            "node": "HTTP Scraptio",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "If Error, Break",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Suppliers Exist, Continue": {
      "main": [
        [
          {
            "node": "If Error, Break",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Preparing Suppliers as Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Preparing Suppliers as Items": {
      "main": [
        [
          {
            "node": "Supplier Validator Sub Workflow",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "If Error, Break",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supplier Validator Sub Workflow": {
      "main": [
        [
          {
            "node": "Aggregating Validated Suppliers",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregating Validated Suppliers": {
      "main": [
        [
          {
            "node": "Preparing Variables for Ranking",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Preparing Variables for Ranking": {
      "main": [
        [
          {
            "node": "Ranking",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Ranking": {
      "main": [
        [
          {
            "node": "Inserting Articles to Ranking Table",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Inserting Articles to Ranking Table": {
      "main": [
        [
          {
            "node": "Loop Over Links",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Error, Break": {
      "main": [
        [
          {
            "node": "Loop Over Links",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Retrieving Articles with Rank 4": {
      "main": [
        [
          {
            "node": "Calculating Final Score and Appending Mentioned Links",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculating Final Score and Appending Mentioned Links": {
      "main": [
        [
          {
            "node": "Loop Over Suppliers",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Suppliers": {
      "main": [
        [
          {
            "node": "Merge Outputs",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Selecting Supplier ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Selecting Supplier ID": {
      "main": [
        [
          {
            "node": "If Exists, Continue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Exists, Continue": {
      "main": [
        [
          {
            "node": "If Error, Break1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Calculating New Score",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Error, Break1": {
      "main": [
        [
          {
            "node": "Loop Over Suppliers",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculating New Score": {
      "main": [
        [
          {
            "node": "Updating Final Score",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Updating Final Score": {
      "main": [
        [
          {
            "node": "Loop Over Suppliers",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Outputs": {
      "main": [
        [
          {
            "node": "Send Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 10 min": {
      "main": [
        [
          {
            "node": "Scrape Second",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 20 min": {
      "main": [
        [
          {
            "node": "Scrape Third",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extractor Agent": {
      "main": [
        [
          {
            "node": "If Suppliers Exist, Continue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Extractor Agent",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model2": {
      "ai_languageModel": [
        [
          {
            "node": "Extractor Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model with Langfuse3": {
      "ai_languageModel": [
        []
      ]
    },
    "Code1": {
      "main": [
        [
          {
            "node": "Loop Over Links",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "inference the Query Generator Agent": {
      "main": [
        [
          {
            "node": "Code1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Scraptio": {
      "main": [
        [
          {
            "node": "Extractor Agent",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "First Scrape",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrape Second": {
      "main": [
        [
          {
            "node": "Extractor Agent",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait 20 min",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "First Scrape": {
      "main": [
        [
          {
            "node": "Extractor Agent",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait 10 min",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrape Third": {
      "main": [
        [
          {
            "node": "Extractor Agent",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "If Error, Break",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": null,
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "versionId": "9f812cba-f4ee-46df-b147-48cfc94d3ef2",
  "activeVersionId": "9f812cba-f4ee-46df-b147-48cfc94d3ef2",
  "versionCounter": 27,
  "triggerCount": 1,
  "tags": [],
  "shared": [
    {
      "updatedAt": "2025-12-10T10:46:11.627Z",
      "createdAt": "2025-12-10T10:46:11.627Z",
      "role": "workflow:owner",
      "workflowId": "nLRVXwucw7o8stSe",
      "projectId": "djYaStOn9zI5EsPo",
      "project": {
        "updatedAt": "2025-09-15T16:43:28.477Z",
        "createdAt": "2025-08-12T10:01:21.384Z",
        "id": "djYaStOn9zI5EsPo",
        "name": "alaeddine mansouri <alaeddine.mansouri@apaia-technology.io>",
        "type": "personal",
        "icon": null,
        "description": null,
        "creatorId": "4a26304c-2848-4f11-9dde-91390758dc98"
      }
    }
  ]
}

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

Sourcing_Multi_Agent_After_Articles_Discovery_Pipeline. Uses mySql, emailSend, chainLlm, outputParserStructured. Webhook trigger; 49 nodes.

Source: https://github.com/alaeddine-hash/docker-n8n-exports/blob/main/Sourcing_Multi_Agent_After_Articles_Discovery_Pipeline__7d7788bb-c533-40a5-93c4-8fdf5deddc0a.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

LLMS_Query_Links_stabilisation. Uses mySql, lmChatOpenAi, executeCommand, chainLlm. Webhook trigger; 95 nodes.

MySQL, OpenAI Chat, Execute Command +6
AI & RAG

LLMS_Query_Links_stabilisation. Uses mySql, lmChatOpenAi, executeCommand, chainLlm. Webhook trigger; 95 nodes.

MySQL, OpenAI Chat, Execute Command +6
AI & RAG

sourcing_agent_production. Uses mySql, openAi, executeCommand, emailSend. Webhook trigger; 78 nodes.

MySQL, OpenAI, Execute Command +5
AI & RAG

sourcing_agent_production. Uses mySql, openAi, executeCommand, emailSend. Webhook trigger; 78 nodes.

MySQL, OpenAI, Execute Command +5
AI & RAG

Sourcing_Multi_Agent_After_Articles_Discovery_Pipeline. Uses mySql, emailSend, chainLlm, outputParserStructured. Webhook trigger; 49 nodes.

MySQL, Email Send, Chain Llm +5