AutomationFlowsSlack & Telegram › Multi Capture

Multi Capture

Multi_Capture. Uses executeWorkflowTrigger, httpRequest, chainLlm, lmChatOpenRouter. Event-driven trigger; 25 nodes.

Event trigger★★★★☆ complexityAI-powered25 nodesExecute Workflow TriggerHTTP RequestChain LlmOpenRouter ChatDiscord
Slack & Telegram Trigger: Event Nodes: 25 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow follows the Chainllm → Execute Workflow Trigger 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
{
  "updatedAt": "2025-12-24T09:35:09.881Z",
  "createdAt": "2025-12-23T09:30:29.836Z",
  "id": "DX0m48INGS7vEwbu",
  "name": "Multi_Capture",
  "description": null,
  "active": false,
  "isArchived": false,
  "nodes": [
    {
      "parameters": {
        "inputSource": "passthrough"
      },
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1.1,
      "position": [
        -1600,
        944
      ],
      "id": "trigger-multi-extract",
      "name": "ExecuteWorkflowTrigger"
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Prepare for multi-capture\nconst ctx = $json.ctx;\n\nreturn  {\n      ctx: ctx,\n      inference_start: Date.now()\n    }"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -1376,
        848
      ],
      "id": "prepare-extraction",
      "name": "PrepareCapture"
    },
    {
      "parameters": {
        "method": "DELETE",
        "url": "=https://discord.com/api/v10/channels/{{ $json.ctx.event.channel_id }}/messages/{{ $json.ctx.event.message_id }}/reactions/\ud83d\udd35/@me",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "discordBotApi",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -1376,
        1040
      ],
      "id": "remove-blue-reaction",
      "name": "Remove\ud83d\udd35Reaction",
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 1000,
      "credentials": {
        "discordBotApi": {
          "name": "<your credential>"
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=You are an extraction agent for a life-tracking system. Analyze the message and extract all relevant items.\n\n## Message to Analyze\n\n\"{{ $json.ctx.event.clean_text }}\"\n\n## Extraction Types\n\n### Activity (what the user is doing NOW)\nExtract if the message describes a CURRENT or RECENT action by the user.\n- **Categories:** work, leisure, study, health, sleep, relationships, admin\n- **Indicators:** \"I am\", \"I'm\", \"-ing verbs\", \"just did\", present/recent past tense\n\n### Note (observation, insight, or fact worth remembering)\nExtract if the message contains knowledge, observations, or reflections.\n- **Categories:** reflection (about self), fact (about world/others)\n- **Indicators:** observations about things/people, realizations, ideas, decisions\n\n### Todo (actionable task to complete)\nExtract if the message contains a clear task to do later.\n- **Priority:** high, medium, low\n- **Indicators:** \"need to\", \"should\", \"have to\", \"TODO\", future tasks\n\n## Key Rules\n\n1. A message can have 0, 1, 2, or 3 extractions\n2. Set confidence 0.0-1.0 based on how clearly the message indicates each type\n3. Only include extractions with confidence >= 0.5\n4. Prefer fewer high-confidence extractions over many low-confidence ones\n5. Activity describes what I'M doing; Note describes observations about anything else\n\n## Output Format\n\nOutput ONLY valid JSON, no explanation:\n\n{\"activity\": {\"category\": \"work\", \"description\": \"debugging auth\", \"confidence\": 0.92}, \"note\": {\"category\": \"reflection\", \"text\": \"noticed pattern in logs\", \"confidence\": 0.78}, \"todo\": null}",
        "needsFallback": true,
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.7,
      "position": [
        -1152,
        848
      ],
      "id": "multi-extractor",
      "name": "MultiCapturer"
    },
    {
      "parameters": {
        "model": "xiaomi/mimo-v2-flash:free",
        "options": {
          "timeout": 15000
        }
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "typeVersion": 1,
      "position": [
        -1152,
        1072
      ],
      "id": "mimo-v2-flash",
      "name": "MimoV2Flash",
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "model": "nvidia/nemotron-nano-9b-v2:free",
        "options": {
          "timeout": 15000
        }
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "typeVersion": 1,
      "position": [
        -1024,
        1072
      ],
      "id": "nemotron-nano-9b",
      "name": "NemotronNano9b",
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Parse LLM response, filter by confidence, build trace query\nconst EMOJI = { activity: '\ud83d\udd18', note: '\ud83d\udcdd', todo: '\u2705' };\nconst CONFIDENCE_THRESHOLD = 0.5;\n\nconst llmText = $json.text?.trim() || '';\nconst prepareItem = $('PrepareCapture').first().json;\nconst ctx = prepareItem.ctx;\nconst durationMs = Date.now() - prepareItem.inference_start;\n\n// Full rendered prompt (template + input)\nconst fullPrompt = `You are an extraction agent for a life-tracking system. Analyze the message and extract all relevant items.\n\n## Message to Analyze\n\n\"${ctx.event.clean_text}\"\n\n## Extraction Types\n\n### Activity (what the user is doing NOW)\nExtract if the message describes a CURRENT or RECENT action by the user.\n- **Categories:** work, leisure, study, health, sleep, relationships, admin\n- **Indicators:** \"I am\", \"I'm\", \"-ing verbs\", \"just did\", present/recent past tense\n\n### Note (observation, insight, or fact worth remembering)\nExtract if the message contains knowledge, observations, or reflections.\n- **Categories:** reflection (about self), fact (about world/others)\n- **Indicators:** observations about things/people, realizations, ideas, decisions\n\n### Todo (actionable task to complete)\nExtract if the message contains a clear task to do later.\n- **Priority:** high, medium, low\n- **Indicators:** \"need to\", \"should\", \"have to\", \"TODO\", future tasks\n\n## Key Rules\n\n1. A message can have 0, 1, 2, or 3 extractions\n2. Set confidence 0.0-1.0 based on how clearly the message indicates each type\n3. Only include extractions with confidence >= 0.5\n4. Prefer fewer high-confidence extractions over many low-confidence ones\n5. Activity describes what I'M doing; Note describes observations about anything else\n\n## Output Format\n\nOutput ONLY valid JSON, no explanation:\n\n{\"activity\": {\"category\": \"work\", \"description\": \"debugging auth\", \"confidence\": 0.92}, \"note\": {\"category\": \"reflection\", \"text\": \"noticed pattern in logs\", \"confidence\": 0.78}, \"todo\": null}`;\n\n// Format trace_chain for PostgreSQL\nconst traceChain = ctx.event.trace_chain || [];\nconst traceChainPg = '{' + traceChain.join(',') + '}';\n\n// Parse JSON from LLM output\nlet parsed = { activity: null, note: null, todo: null };\nlet parseError = null;\n\ntry {\n  let jsonStr = llmText;\n  const codeBlock = llmText.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n  if (codeBlock) jsonStr = codeBlock[1].trim();\n  const objMatch = jsonStr.match(/\\{[\\s\\S]*\\}/);\n  if (objMatch) jsonStr = objMatch[0];\n  parsed = JSON.parse(jsonStr);\n} catch (e) {\n  parseError = e.message;\n}\n\n// Build captures array\nconst captures = [];\nconst emojis = [];\n\nif (parsed.activity?.confidence >= CONFIDENCE_THRESHOLD) {\n  captures.push({\n    type: 'activity',\n    emoji: EMOJI.activity,\n    data: {\n      timestamp: new Date().toISOString(),\n      category: parsed.activity.category || 'work',\n      description: parsed.activity.description || ctx.event.clean_text,\n      message_url: ctx.event.message_url,\n      confidence: parsed.activity.confidence\n    }\n  });\n  emojis.push(EMOJI.activity);\n}\n\nif (parsed.note?.confidence >= CONFIDENCE_THRESHOLD) {\n  captures.push({\n    type: 'note',\n    emoji: EMOJI.note,\n    data: {\n      timestamp: new Date().toISOString(),\n      category: parsed.note.category || 'reflection',\n      text: parsed.note.text || ctx.event.clean_text,\n      message_url: ctx.event.message_url,\n      confidence: parsed.note.confidence\n    }\n  });\n  emojis.push(EMOJI.note);\n}\n\nif (parsed.todo?.confidence >= CONFIDENCE_THRESHOLD) {\n  captures.push({\n    type: 'todo',\n    emoji: EMOJI.todo,\n    data: {\n      timestamp: new Date().toISOString(),\n      priority: parsed.todo.priority || 'medium',\n      text: parsed.todo.text || ctx.event.clean_text,\n      message_url: ctx.event.message_url,\n      confidence: parsed.todo.confidence\n    }\n  });\n  emojis.push(EMOJI.todo);\n}\n\n// Fallback: if nothing captured, create low-confidence note\nif (captures.length === 0) {\n  captures.push({\n    type: 'note',\n    emoji: EMOJI.note,\n    data: {\n      timestamp: new Date().toISOString(),\n      category: 'reflection',\n      text: ctx.event.clean_text,\n      message_url: ctx.event.message_url,\n      confidence: 0.3\n    }\n  });\n  emojis.push(EMOJI.note);\n}\n\n// Pre-stringify the result for postgres jsonb\nconst resultJson = JSON.stringify(captures.map(c => ({ type: c.type, confidence: c.data.confidence })));\n\n// Return with ctx.db_queries for Execute_Queries\nreturn [{\n  json: {\n    ctx: {\n      ...ctx,\n      db_queries: [{\n        key: 'trace',\n        sql: `INSERT INTO traces (event_id, step_name, data, trace_chain)\nVALUES (\n  $1::uuid,\n  'multi_capture',\n  jsonb_build_object(\n    'prompt', $2,\n    'input', jsonb_build_object('text', $3),\n    'completion', $4,\n    'result', $5::jsonb,\n    'model', 'xiaomi/mimo-v2-flash:free',\n    'duration_ms', $6::integer,\n    'capture_count', $7::integer\n  ),\n  $8::uuid[]\n)\nRETURNING id, trace_chain || id AS updated_trace_chain;`,\n        params: [\n          ctx.event.event_id,\n          fullPrompt,\n          ctx.event.clean_text,\n          llmText,\n          resultJson,\n          durationMs,\n          captures.length,\n          traceChainPg\n        ]\n      }]\n    },\n    captures,\n    emojis,\n    total_captures: captures.length,\n    raw_response: llmText,\n    parse_error: parseError,\n    duration_ms: durationMs\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -800,
        848
      ],
      "id": "parse-and-split",
      "name": "ParseResponse"
    },
    {
      "parameters": {
        "workflowId": {
          "__rl": true,
          "value": "CgUAxK0i4YhrZ2Wp",
          "mode": "list",
          "cachedResultName": "Execute_Queries",
          "cachedResultUrl": "/workflow/CgUAxK0i4YhrZ2Wp"
        },
        "workflowInputs": {
          "mappingMode": "defineBelow",
          "value": {
            "ctx": "={{ $json.ctx }}"
          }
        },
        "options": {
          "waitForSubWorkflow": true
        }
      },
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.3,
      "position": [
        -576,
        848
      ],
      "id": "store-llm-trace",
      "name": "StoreLlmTrace"
    },
    {
      "parameters": {
        "jsCode": "// Split captures into individual items for projection storage\n// Input: Store LLM Trace result (ctx with db.trace)\n// Output: One item per capture, each with trace_id attached\n\nconst ctx = $json.ctx;\nconst parseResult = $('ParseResponse').first().json;\n\nconst llmTraceId = ctx.db?.trace?.row?.id;\nconst updatedTraceChain = ctx.db?.trace?.row?.updated_trace_chain || [];\nconst updatedTraceChainPg = '{' + updatedTraceChain.join(',') + '}';\n\n// Split captures array into individual items, each with its own db_queries\nreturn parseResult.captures.map(capture => ({\n  json: {\n    ctx: {\n      ...ctx,\n      db_queries: [{\n        key: 'projection',\n        sql: `INSERT INTO projections (trace_id, event_id, trace_chain, projection_type, data, status, timezone)\nVALUES (\n  $1::uuid,\n  $2::uuid,\n  $3::uuid[],\n  $4,\n  $5::jsonb,\n  'auto_confirmed',\n  $6\n)\nRETURNING *;`,\n        params: [\n          llmTraceId,\n          ctx.event.event_id,\n          updatedTraceChainPg,\n          capture.type,\n          JSON.stringify(capture.data),\n          ctx.event.timezone\n        ]\n      }]\n    },\n    capture\n  }\n}));"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -352,
        848
      ],
      "id": "prepare-projections",
      "name": "SplitCaptures"
    },
    {
      "parameters": {
        "workflowId": {
          "__rl": true,
          "value": "CgUAxK0i4YhrZ2Wp",
          "mode": "list",
          "cachedResultName": "Execute_Queries",
          "cachedResultUrl": "/workflow/CgUAxK0i4YhrZ2Wp"
        },
        "workflowInputs": {
          "mappingMode": "defineBelow",
          "value": {
            "ctx": "={{ $json.ctx }}"
          }
        },
        "options": {
          "waitForSubWorkflow": true
        }
      },
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.3,
      "position": [
        128,
        848
      ],
      "id": "store-projection",
      "name": "StoreProjection"
    },
    {
      "parameters": {
        "jsCode": "// Collect results for logging with standard emojis\nconst parseResult = $('ParseResponse').first().json;\n\n// Standard emoji mapping\nconst typeEmojis = {\n  'activity': '\ud83d\udd18',\n  'note': '\ud83d\udcdd',\n  'todo': '\ud83d\udd32'\n};\n\n// Map capture types to standard emojis\nconst emojis = parseResult.captures.map(c => typeEmojis[c.type] || '\ud83d\udce6');\n\n// Build verbose config query\nreturn [{\n  json: {\n    ctx: {\n      ...parseResult.ctx,\n      db_queries: [{\n        key: 'verbose_config',\n        sql: `SELECT value FROM config WHERE key = 'verbose'`,\n        params: []\n      }]\n    },\n    emojis: emojis,\n    duration_ms: parseResult.duration_ms,\n    projection_count: parseResult.total_captures\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -576,
        1040
      ],
      "id": "collect-results",
      "name": "CollectResults"
    },
    {
      "parameters": {
        "method": "PUT",
        "url": "=https://discord.com/api/v10/channels/{{ $json.ctx.event.channel_id }}/messages/{{ $json.ctx.event.message_id }}/reactions/{{ $json.emoji }}/@me",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "discordBotApi",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -128,
        528
      ],
      "id": "add-emoji-reactions",
      "name": "AddEmojiReactions",
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 1000,
      "credentials": {
        "discordBotApi": {
          "name": "<your credential>"
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "resource": "message",
        "guildId": {
          "__rl": true,
          "value": "={{ $json.ctx.event.guild_id }}",
          "mode": "id"
        },
        "channelId": {
          "__rl": true,
          "value": "={{ $env.DISCORD_CHANNEL_KAIRON_LOGS }}",
          "mode": "id"
        },
        "content": "={{ $json.ctx.event.clean_text }} {{ $json.duration_ms }}ms \u27a1\ufe0f {{ $json.emojis.join(' ') }}",
        "options": {}
      },
      "type": "n8n-nodes-base.discord",
      "typeVersion": 2,
      "position": [
        -352,
        1232
      ],
      "id": "log-to-kairon-logs",
      "name": "LogToKaironLogs",
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 1000,
      "credentials": {
        "discordBotApi": {
          "name": "<your credential>"
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "amount": 1
      },
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        96,
        560
      ],
      "id": "wait-rate-limit",
      "name": "Wait1s"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        -352,
        560
      ],
      "id": "2741faa1-e8ab-4588-b3b5-bc67839680a3",
      "name": "LoopOverItems"
    },
    {
      "parameters": {
        "jsCode": "// Convert emojis array to individual items for batch processing\nconst parseResult = $('ParseResponse').first().json;\n\n// Standard emoji mapping\nconst typeEmojis = {\n  'activity': '\ud83d\udd18',\n  'note': '\ud83d\udcdd',\n  'todo': '\ud83d\udd32'\n};\n\n// Map capture types to standard emojis\nconst emojis = parseResult.captures.map(c => typeEmojis[c.type] || '\ud83d\udce6');\n\nreturn emojis.map(emoji => ({\n  json: {\n    ctx: parseResult.ctx,\n    emoji: emoji\n  }\n}));"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -576,
        560
      ],
      "id": "prepare-emoji-items",
      "name": "PrepareEmojiItems"
    },
    {
      "parameters": {
        "workflowId": {
          "__rl": true,
          "value": "CgUAxK0i4YhrZ2Wp",
          "mode": "list",
          "cachedResultName": "Execute_Queries",
          "cachedResultUrl": "/workflow/CgUAxK0i4YhrZ2Wp"
        },
        "workflowInputs": {
          "mappingMode": "defineBelow",
          "value": {
            "ctx": "={{ $json.ctx }}"
          }
        },
        "options": {
          "waitForSubWorkflow": true
        }
      },
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.3,
      "position": [
        -352,
        1040
      ],
      "id": "query-verbose-setting",
      "name": "QueryVerboseSetting"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "f55070f3-80b6-4076-a05d-6799052b6555",
              "leftValue": "={{ $json.ctx.verbose }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        96,
        1040
      ],
      "id": "if-verbose-true",
      "name": "IfVerboseTrue"
    },
    {
      "parameters": {
        "workflowId": {
          "__rl": true,
          "value": "wVpslhMBnrsgDaOR",
          "mode": "list",
          "cachedResultName": "Show_Projection_Details",
          "cachedResultUrl": "/workflow/wVpslhMBnrsgDaOR"
        },
        "workflowInputs": {
          "mappingMode": "defineBelow",
          "value": {
            "ctx": "={{ $json.ctx }}"
          }
        },
        "options": {
          "waitForSubWorkflow": false
        }
      },
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.3,
      "position": [
        320,
        1040
      ],
      "id": "trigger-show-details",
      "name": "TriggerShowDetails"
    },
    {
      "parameters": {
        "jsCode": "// Merge verbose config result into ctx\nconst collectResults = $('CollectResults').first().json;\nconst ctx = $json.ctx;\nconst verboseValue = ctx.db?.verbose_config?.row?.value;\n\nreturn [{\n  json: {\n    ctx: {\n      ...ctx,\n      verbose: verboseValue === 'true' || verboseValue === true\n    },\n    emojis: collectResults.emojis,\n    duration_ms: collectResults.duration_ms,\n    projection_count: collectResults.projection_count\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -128,
        1040
      ],
      "id": "merge-ctx-verbose",
      "name": "MergeCtxForVerbose"
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Extract text for embedding from projection data\nconst ctx = $json.ctx;\nconst projection = ctx.db?.projection?.row || {};\nconst data = projection.data || {};\nconst embeddingText = data.description || data.text || '';\n\nreturn {\n      projection_id: projection.id,\n      embedding_text: embeddingText\n    }"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        352,
        848
      ],
      "id": "prepare-embedding-text",
      "name": "PrepareEmbeddingText"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $env.EMBEDDING_SERVICE_URL }}/embed",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"texts\": [{{ JSON.stringify($json.embedding_text || '') }}]\n}",
        "options": {
          "timeout": 10000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        576,
        848
      ],
      "id": "embed-projection-text",
      "name": "EmbedProjectionText",
      "continueOnFail": true
    },
    {
      "parameters": {
        "jsCode": "// Build embedding insert query for Execute_Queries\nconst prepareData = $(\"PrepareEmbeddingText\").first().json;\nconst embeddings = $json.embeddings;\n\n// Check if we have a valid embedding\nif (!embeddings || !embeddings[0]) {\n  // Return a pass-through item to keep the loop going\n  return [{\n    json: {\n      ctx: {\n        ...($json.ctx || {}),\n        db_queries: []  // Empty queries = no-op in Execute_Queries\n      }\n    }\n  }];\n}\n\nconst embeddingVector = \"[\" + embeddings[0].join(\",\") + \"]\";\n\nreturn [{\n  json: {\n    ctx: {\n      ...($json.ctx || {}),\n      db_queries: [{\n        key: \"embedding\",\n        sql: `-- Insert embedding for the projection (fire-and-forget)\nINSERT INTO embeddings (projection_id, model, embedding_data, embedded_text, embedding)\nSELECT \n  $1::uuid,\n  \"all-MiniLM-L6-v2\",\n  \"{}\",\n  $2,\n  $3::vector\nWHERE $3 IS NOT NULL\nON CONFLICT DO NOTHING;`,\n        params: [\n          prepareData.projection_id,\n          prepareData.embedding_text,\n          embeddingVector\n        ]\n      }]\n    }\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        800,
        848
      ],
      "id": "build-embedding-query",
      "name": "BuildEmbeddingQuery"
    },
    {
      "parameters": {
        "workflowId": {
          "__rl": true,
          "value": "CgUAxK0i4YhrZ2Wp",
          "mode": "list",
          "cachedResultName": "Execute_Queries",
          "cachedResultUrl": "/workflow/CgUAxK0i4YhrZ2Wp"
        },
        "workflowInputs": {
          "mappingMode": "defineBelow",
          "value": {
            "ctx": "={{ $json.ctx }}"
          }
        },
        "options": {
          "waitForSubWorkflow": true
        }
      },
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.3,
      "position": [
        1024,
        848
      ],
      "id": "insert-embedding",
      "name": "InsertEmbedding",
      "continueOnFail": true
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        -128,
        848
      ],
      "id": "projection-loop",
      "name": "ProjectionLoop"
    }
  ],
  "connections": {
    "ExecuteWorkflowTrigger": {
      "main": [
        [
          {
            "node": "PrepareCapture",
            "type": "main",
            "index": 0
          },
          {
            "node": "Remove\ud83d\udd35Reaction",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "PrepareCapture": {
      "main": [
        [
          {
            "node": "MultiCapturer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "MultiCapturer": {
      "main": [
        [
          {
            "node": "ParseResponse",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "StoreLlmTrace": {
      "main": [
        [
          {
            "node": "SplitCaptures",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "StoreProjection": {
      "main": [
        [
          {
            "node": "PrepareEmbeddingText",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "PrepareEmbeddingText": {
      "main": [
        [
          {
            "node": "EmbedProjectionText",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "EmbedProjectionText": {
      "main": [
        [
          {
            "node": "BuildEmbeddingQuery",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "BuildEmbeddingQuery": {
      "main": [
        [
          {
            "node": "InsertEmbedding",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CollectResults": {
      "main": [
        [
          {
            "node": "LogToKaironLogs",
            "type": "main",
            "index": 0
          },
          {
            "node": "QueryVerboseSetting",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AddEmojiReactions": {
      "main": [
        [
          {
            "node": "Wait1s",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "MimoV2Flash": {
      "ai_languageModel": [
        [
          {
            "node": "MultiCapturer",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "NemotronNano9b": {
      "ai_languageModel": [
        [
          {
            "node": "MultiCapturer",
            "type": "ai_languageModel",
            "index": 1
          }
        ]
      ]
    },
    "Wait1s": {
      "main": [
        [
          {
            "node": "LoopOverItems",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "LoopOverItems": {
      "main": [
        [],
        [
          {
            "node": "AddEmojiReactions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ParseResponse": {
      "main": [
        [
          {
            "node": "StoreLlmTrace",
            "type": "main",
            "index": 0
          },
          {
            "node": "CollectResults",
            "type": "main",
            "index": 0
          },
          {
            "node": "PrepareEmojiItems",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SplitCaptures": {
      "main": [
        [
          {
            "node": "ProjectionLoop",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "PrepareEmojiItems": {
      "main": [
        [
          {
            "node": "LoopOverItems",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "LogToKaironLogs": {
      "main": [
        []
      ]
    },
    "QueryVerboseSetting": {
      "main": [
        [
          {
            "node": "MergeCtxForVerbose",
            "index": 0,
            "type": "main"
          }
        ]
      ]
    },
    "IfVerboseTrue": {
      "main": [
        [
          {
            "node": "TriggerShowDetails",
            "index": 0,
            "type": "main"
          }
        ]
      ]
    },
    "MergeCtxForVerbose": {
      "main": [
        [
          {
            "node": "IfVerboseTrue",
            "index": 0,
            "type": "main"
          }
        ]
      ]
    },
    "ProjectionLoop": {
      "main": [
        [],
        [
          {
            "node": "StoreProjection",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "InsertEmbedding": {
      "main": [
        [
          {
            "node": "ProjectionLoop",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": "NOJ7FqVhVLqw0n8D",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "staticData": null,
  "meta": null,
  "versionId": "5edea6c3-4c7e-46ee-90c3-ba9dd4b97587",
  "activeVersionId": null,
  "versionCounter": 231,
  "triggerCount": 0,
  "shared": [
    {
      "updatedAt": "2025-12-23T09:30:29.836Z",
      "createdAt": "2025-12-23T09:30:29.836Z",
      "role": "workflow:owner",
      "workflowId": "DX0m48INGS7vEwbu",
      "projectId": "erM3nntdLL53noWi",
      "project": {
        "updatedAt": "2025-12-23T09:23:39.658Z",
        "createdAt": "2025-12-23T09:16:56.460Z",
        "id": "erM3nntdLL53noWi",
        "name": "Chris Irineo <chriskevini@gmail.com>",
        "type": "personal",
        "icon": null,
        "description": null,
        "projectRelations": [
          {
            "updatedAt": "2025-12-23T09:16:56.460Z",
            "createdAt": "2025-12-23T09:16:56.460Z",
            "userId": "2a851a2d-b7e5-4b3c-aefb-6eaaa79e0659",
            "projectId": "erM3nntdLL53noWi",
            "user": {
              "updatedAt": "2025-12-24T08:40:46.063Z",
              "createdAt": "2025-12-23T09:16:54.881Z",
              "id": "2a851a2d-b7e5-4b3c-aefb-6eaaa79e0659",
              "email": "chriskevini@gmail.com",
              "firstName": "Chris",
              "lastName": "Irineo",
              "personalizationAnswers": {
                "version": "v4",
                "personalization_survey_submitted_at": "2025-12-23T09:23:43.723Z",
                "personalization_survey_n8n_version": "1.123.5"
              },
              "settings": {
                "userActivated": true,
                "firstSuccessfulWorkflowId": "CgUAxK0i4YhrZ2Wp",
                "userActivatedAt": 1766487000077,
                "easyAIWorkflowOnboarded": true
              },
              "disabled": false,
              "mfaEnabled": false,
              "lastActiveAt": "2025-12-24",
              "isPending": false
            }
          }
        ]
      }
    }
  ],
  "tags": [],
  "activeVersion": null
}

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

Multi_Capture. Uses executeWorkflowTrigger, httpRequest, chainLlm, lmChatOpenRouter. Event-driven trigger; 25 nodes.

Source: https://github.com/chriskevini/kairon/blob/ab924f228ceb22522b9a4dfa1ab4589eb86273ad/n8n-workflows/Multi_Capture.json — original creator credit. Request a take-down →

More Slack & Telegram workflows → · Browse all categories →

Related workflows

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

Slack & Telegram

Capture_Thread. Uses executeWorkflowTrigger, chainLlm, httpRequest, discord. Event-driven trigger; 26 nodes.

Execute Workflow Trigger, Chain Llm, HTTP Request +2
Slack & Telegram

Capture_Projection. Uses executeWorkflowTrigger, httpRequest, chainLlm, lmChatOpenRouter. Event-driven trigger; 18 nodes.

Execute Workflow Trigger, HTTP Request, Chain Llm +2
Slack & Telegram

Continue_Thread. Uses executeWorkflowTrigger, chainLlm, lmChatOpenRouter, discord. Event-driven trigger; 14 nodes.

Execute Workflow Trigger, Chain Llm, OpenRouter Chat +2
Slack & Telegram

Start_Thread. Uses executeWorkflowTrigger, httpRequest, chainLlm, lmChatOpenRouter. Event-driven trigger; 14 nodes.

Execute Workflow Trigger, HTTP Request, Chain Llm +2
Slack & Telegram

This workflow is designed for n8n users who manage multiple production workflows and want to: Receive intelligent, actionable error alerts instead of raw stack traces Understand root causes without ma

Error Trigger, Chain Llm, Gmail +5