{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "be902a85-fc31-442c-b308-a2350ec5aabb",
      "name": "When clicking \u2018Test workflow\u2019",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -760,
        440
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "d229b686-9de4-4633-9dba-3e1fe71eedf1",
      "name": "No Operation, do nothing1",
      "type": "n8n-nodes-base.noOp",
      "position": [
        1820,
        800
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "f583bc97-8da8-488e-ab04-5167dc7a7701",
      "name": "Information Extractor",
      "type": "@n8n/n8n-nodes-langchain.informationExtractor",
      "position": [
        2420,
        540
      ],
      "parameters": {
        "text": "={{ $json.buffer.reverse().toJsonString() }}",
        "options": {
          "systemPromptTemplate": "Eres un experto extrayendo informaci\u00f3n, tu objetivo es recolectar todos los mensajes. Procura no dejar duplicados. como resultado debes retornar un solo p\u00e1rrafo con todo los mensajes."
        },
        "schemaType": "fromJson",
        "jsonSchemaExample": "{\n\t\"message\": \"all consolidated messages\"\n}"
      },
      "typeVersion": 1
    },
    {
      "id": "5b719416-4886-4d38-9d00-30b6237db168",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        2440,
        760
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-nano",
          "cachedResultName": "gpt-4.1-nano"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "3d149fc0-caa7-4361-9bf9-33b6252b39eb",
      "name": "get wait seconds",
      "type": "n8n-nodes-base.code",
      "position": [
        -260,
        500
      ],
      "parameters": {
        "jsCode": "// Function: Compute waitSeconds\nconst wordCount = $json.message.split(' ').filter(w=>w).length;\nreturn [{ json: { \n  context_id: $json.context_id,\n  message: $json.message,\n  waitSeconds: wordCount < 5 ? 45 : 30 \n}}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "cc670735-d126-465f-b0a3-3a4c5e390fd7",
      "name": "Set last_seen",
      "type": "n8n-nodes-base.redis",
      "position": [
        280,
        380
      ],
      "parameters": {
        "key": "=last_seen:{{ $json.context_id}}",
        "ttl": "={{ $json.waitSeconds + 60 }}",
        "value": "={{$now.toMillis()}}",
        "expire": true,
        "keyType": "string",
        "operation": "set"
      },
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "20d97d1d-70d4-4c3c-aa12-b1aa31795240",
      "name": "Get waiting_reply",
      "type": "n8n-nodes-base.redis",
      "position": [
        180,
        780
      ],
      "parameters": {
        "key": "=waiting_reply:{{$json.context_id}}",
        "options": {},
        "operation": "get",
        "propertyName": "waiting_reply"
      },
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "7a2fc681-692f-4f72-9fab-f3ada4bda54b",
      "name": "Mod input",
      "type": "n8n-nodes-base.set",
      "position": [
        340,
        800
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "7ff99444-753d-4ef7-865c-7115761526b8",
              "name": "waiting_reply",
              "type": "string",
              "value": "={{ $json.waiting_reply }}"
            },
            {
              "id": "58ad6981-c35a-4dd6-b1cd-7c446b85e738",
              "name": "context_id",
              "type": "string",
              "value": "={{$('When Executed by Another Workflow').item.json.context_id  }}"
            },
            {
              "id": "bd0535a2-be03-436b-8a2e-222c3e26fd04",
              "name": "message",
              "type": "string",
              "value": "={{$('When Executed by Another Workflow').item.json.message }}"
            },
            {
              "id": "2f583f32-f231-4407-b773-c08b38d464f0",
              "name": "waitSeconds",
              "type": "number",
              "value": "={{ $('get wait seconds').item.json.waitSeconds }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "84213bef-32be-4cd9-8387-cd76aff5cb38",
      "name": "waiting_reply?",
      "type": "n8n-nodes-base.if",
      "position": [
        540,
        800
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "8136ea21-d798-41fd-81ed-5c0e7fda73c5",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.waiting_reply != null}}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "a8472217-aa83-4247-9d7d-3a471e24478a",
      "name": "When chat message received",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        -740,
        640
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1.1
    },
    {
      "id": "ba4c81ba-92e2-4bef-a9e2-6f8d4c0aa722",
      "name": "Set waiting_reply",
      "type": "n8n-nodes-base.redis",
      "position": [
        840,
        720
      ],
      "parameters": {
        "key": "=waiting_reply:{{ $json.context_id }}",
        "ttl": "={{ $json.waitSeconds }}",
        "value": "true",
        "expire": true,
        "operation": "set"
      },
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "0ce783b6-b76b-4a5d-96ae-11708b7532ba",
      "name": "Get buffer",
      "type": "n8n-nodes-base.redis",
      "position": [
        1820,
        600
      ],
      "parameters": {
        "key": "=buffer_in:{{ $('get wait seconds').item.json.context_id }}",
        "options": {},
        "operation": "get",
        "propertyName": "buffer"
      },
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "21864061-1d1f-4528-a03f-1237e9c69a31",
      "name": "Delete buffer_in",
      "type": "n8n-nodes-base.redis",
      "position": [
        2940,
        680
      ],
      "parameters": {
        "key": "=buffer_in:{{$json.context_id}}",
        "operation": "delete"
      },
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "8828aa7b-6153-4677-84a8-3ef2f884792c",
      "name": "Delete waiting_reply",
      "type": "n8n-nodes-base.redis",
      "position": [
        2940,
        840
      ],
      "parameters": {
        "key": "=waiting_reply:{{$json.context_id}}",
        "operation": "delete"
      },
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "fc369067-7213-4d8c-b515-c34c4db997e4",
      "name": "WaitSeconds",
      "type": "n8n-nodes-base.wait",
      "position": [
        1020,
        720
      ],
      "parameters": {
        "amount": "={{ $json.waitSeconds }} "
      },
      "typeVersion": 1.1
    },
    {
      "id": "2daa2ab9-756a-4fdb-8573-b4570c58d6e5",
      "name": "Buffer messages",
      "type": "n8n-nodes-base.redis",
      "position": [
        -40,
        440
      ],
      "parameters": {
        "list": "=buffer_in:{{$json.context_id}}",
        "operation": "push",
        "messageData": "={\"text\": \"{{ $json.message }}\", \"timestamp\": \"{{$now}}\"}"
      },
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "4d5bc5f0-11ce-4f7f-b44b-0514a5ab5671",
      "name": "Set buffer_count increment",
      "type": "n8n-nodes-base.redis",
      "position": [
        280,
        560
      ],
      "parameters": {
        "key": "=buffer_count:{{$json.context_id}}",
        "expire": "={{$json.waitSeconds + 60}}",
        "operation": "incr"
      },
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "dcaee1a8-ea32-4a9d-b32f-f0418644027c",
      "name": "Get last_seen",
      "type": "n8n-nodes-base.redis",
      "position": [
        1220,
        720
      ],
      "parameters": {
        "key": "=last_seen:{{$json.context_id}}",
        "options": {},
        "operation": "get",
        "propertyName": "last_seen"
      },
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "908c4a4c-1c60-4e90-827a-064a0b4d6bfd",
      "name": "Get buffer_count",
      "type": "n8n-nodes-base.redis",
      "position": [
        1400,
        720
      ],
      "parameters": {
        "key": "=buffer_count:{{ $('Mod input').item.json.context_id }}",
        "options": {},
        "operation": "get",
        "propertyName": "count"
      },
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "1ceb472b-3944-4d74-994b-867ade006e4e",
      "name": "Map ouput",
      "type": "n8n-nodes-base.set",
      "position": [
        3140,
        380
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "e8d80ab4-74a2-4c30-8500-8dddc5802eec",
              "name": "message",
              "type": "string",
              "value": "={{ $json.output.message }}"
            },
            {
              "id": "7e7fcee4-14b3-4393-b516-b07a53c018b3",
              "name": "context_id",
              "type": "string",
              "value": "={{$('get wait seconds').item.json.context_id }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "0be7e5eb-1972-4a95-b5bf-4e564fc4ef7c",
      "name": "Check Inactivity + Count",
      "type": "n8n-nodes-base.if",
      "position": [
        1580,
        720
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "0f294c51-0629-4ae1-a009-68c2f5fd30b5",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{$json.count != null && Number($json.count) >= 1}}",
              "rightValue": ""
            },
            {
              "id": "1626238d-fb00-4ce8-89df-a40a4f29f52a",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{$('Get last_seen').item.json.last_seen != null}}",
              "rightValue": ""
            },
            {
              "id": "df819099-1f6e-4bee-a017-32b729c836a3",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{($now.toMillis() - $('Get last_seen').item.json.last_seen) >= $('Mod input').item.json.waitSeconds * 1000}}",
              "rightValue": ""
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "0c3bd62b-8cf6-4b34-8010-ebe819db9667",
      "name": "Delete waiting_reply1",
      "type": "n8n-nodes-base.redis",
      "position": [
        2940,
        1000
      ],
      "parameters": {
        "key": "=buffer_count:{{$json.context_id}}",
        "operation": "delete"
      },
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "bbf45966-833b-4f5f-ae11-0578614eb156",
      "name": "No Operation, do nothing2",
      "type": "n8n-nodes-base.noOp",
      "position": [
        720,
        540
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "5683eebf-ba51-4a6b-a803-de6acf1b1ea8",
      "name": "Wait",
      "type": "n8n-nodes-base.wait",
      "position": [
        2080,
        880
      ],
      "parameters": {
        "amount": "={{ Math.max(0, Math.ceil(( $('Mod input').item.json.waitSeconds * 1000 - ($now.toMillis() - $('Get last_seen').item.json.last_seen)) / 1000)) }}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "c0478f60-944e-4c85-bb9c-9abe0d4238c0",
      "name": "When Executed by Another Workflow",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "position": [
        -480,
        720
      ],
      "parameters": {
        "workflowInputs": {
          "values": [
            {
              "name": "context_id"
            },
            {
              "name": "message"
            }
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "91a650b7-ddd4-4dbf-a300-523f72f0bdb5",
      "name": "Mock input data",
      "type": "n8n-nodes-base.set",
      "position": [
        -500,
        500
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "0543fdb7-4a22-4530-bdb7-ae7064732fae",
              "name": "context_id",
              "type": "string",
              "value": "={{ $json.sessionId1 || '1lap075ha12' }}"
            },
            {
              "id": "bead5646-a689-4deb-8f4b-b22aa97b51ca",
              "name": "message",
              "type": "string",
              "value": "={{ $json.chatInput || 'Chat 2'}}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "cb450e32-7e19-469c-9a5c-3d9da5bf1dfa",
      "name": "No Operation, do nothing3",
      "type": "n8n-nodes-base.noOp",
      "position": [
        3320,
        840
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "b463e405-3355-48a2-a043-42941d7025c3",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2880,
        660
      ],
      "parameters": {
        "color": 7,
        "width": 700,
        "height": 780,
        "content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n### \ud83e\uddf9 Buffer Cleanup\n\nAfter consolidation and reply:\n\n* **DELETE** keys:\n\n  * `buffer_in:{{context_id}}`\n  * `buffer_count:{{context_id}}`\n  * `waiting_reply:{{context_id}}`\n"
      },
      "typeVersion": 1
    },
    {
      "id": "1b5397f8-aa7e-4b2b-afb9-5da97d99e049",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -80,
        60
      ],
      "parameters": {
        "color": 7,
        "width": 920,
        "height": 940,
        "content": "### \ud83d\udce5 Input Buffer\n\n1. **Save incoming message**\n\n   * Push the new message into Redis list `buffer_in:{{context_id}}`.\n2. **Update metadata**\n\n   * Set `last_seen:{{context_id}}` to the current timestamp (with a TTL of `waitSeconds + 60`).\n   * INCR the counter key `buffer_count:{{context_id}}` (also expiring after `waitSeconds + 60`).\n3. **Check \u201cwaiting\u201d flag**\n\n   * GET `waiting_reply:{{context_id}}`.\n   * If it\u2019s null (no batch in flight), SET it to `true` with TTL `waitSeconds` to block concurrent triggers."
      },
      "typeVersion": 1
    },
    {
      "id": "edc07500-ccad-4e72-adc1-1a63a3a06609",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1180,
        340
      ],
      "parameters": {
        "color": 7,
        "width": 1200,
        "height": 820,
        "content": "### \u23f3 Inactivity & Threshold Check\n\n1. **Fetch state**\n\n   * GET `last_seen:{{context_id}}` (when the last message arrived)\n   * GET `buffer_count:{{context_id}}` (how many messages are queued)\n2. **Evaluate trigger**\n\n   * **Inactivity:** `(now \u2013 last_seen) \u2265 waitSeconds * 1000`\n   * **Or threshold:** `buffer_count \u2265 1` (or your desired batch size)\n3. **Branch**\n\n   * **True:** proceed to \u201cGet buffer\u201d and consolidate.\n   * **False:** exit (noOp) and let the waiting\u2010node/flag mechanism retry later."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Wait": {
      "main": [
        [
          {
            "node": "Check Inactivity + Count",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Map ouput": {
      "main": [
        []
      ]
    },
    "Mod input": {
      "main": [
        [
          {
            "node": "waiting_reply?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get buffer": {
      "main": [
        [
          {
            "node": "Information Extractor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "WaitSeconds": {
      "main": [
        [
          {
            "node": "Get last_seen",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get last_seen": {
      "main": [
        [
          {
            "node": "Get buffer_count",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set last_seen": {
      "main": [
        [
          {
            "node": "No Operation, do nothing2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "waiting_reply?": {
      "main": [
        [
          {
            "node": "No Operation, do nothing2",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Set waiting_reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Buffer messages": {
      "main": [
        [
          {
            "node": "Set buffer_count increment",
            "type": "main",
            "index": 0
          },
          {
            "node": "Set last_seen",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get waiting_reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mock input data": {
      "main": [
        [
          {
            "node": "get wait seconds",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Delete buffer_in": {
      "main": [
        [
          {
            "node": "No Operation, do nothing3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get buffer_count": {
      "main": [
        [
          {
            "node": "Check Inactivity + Count",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "get wait seconds": {
      "main": [
        [
          {
            "node": "Buffer messages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get waiting_reply": {
      "main": [
        [
          {
            "node": "Mod input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Information Extractor",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Set waiting_reply": {
      "main": [
        [
          {
            "node": "WaitSeconds",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Delete waiting_reply": {
      "main": [
        [
          {
            "node": "No Operation, do nothing3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Delete waiting_reply1": {
      "main": [
        [
          {
            "node": "No Operation, do nothing3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Information Extractor": {
      "main": [
        [
          {
            "node": "Map ouput",
            "type": "main",
            "index": 0
          },
          {
            "node": "Delete buffer_in",
            "type": "main",
            "index": 0
          },
          {
            "node": "Delete waiting_reply",
            "type": "main",
            "index": 0
          },
          {
            "node": "Delete waiting_reply1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Inactivity + Count": {
      "main": [
        [
          {
            "node": "Get buffer",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "No Operation, do nothing1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "No Operation, do nothing1": {
      "main": [
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set buffer_count increment": {
      "main": [
        [
          {
            "node": "No Operation, do nothing2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When chat message received": {
      "main": [
        [
          {
            "node": "Mock input data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When Executed by Another Workflow": {
      "main": [
        [
          {
            "node": "get wait seconds",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking \u2018Test workflow\u2019": {
      "main": [
        [
          {
            "node": "Mock input data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}