{
  "name": "Telegram Orchestrator",
  "nodes": [
    {
      "parameters": {
        "model": "openai/gpt-oss-20b:free",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "typeVersion": 1,
      "position": [
        480,
        -176
      ],
      "id": "07e8bccc-d199-4212-b226-e40b087d2f5a",
      "name": "Fallback",
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "mode": "raw",
        "jsonOutput": "={\n  \"parameters\": {\n    \"assignments\": {\n      \"assignments\": [\n        {\n          \"id\": \"a1\",\n          \"name\": \"userText\",\n          \"value\": \"{{ $('Telegram Trigger').first().json.message.text || $json.message?.text || '' }}\",\n          \"type\": \"string\"\n        },\n        {\n          \"id\": \"a2\",\n          \"name\": \"chatId\",\n          \"value\": \"{{ $('Telegram Trigger').first().json.message.chat.id }}\",\n          \"type\": \"string\"\n        }\n      ]\n    },\n    \"includeOtherFields\": false,\n    \"options\": {}\n  },\n  \"type\": \"n8n-nodes-base.set\",\n  \"typeVersion\": 3.4,\n  \"name\": \"Normalize Input\"\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        240,
        -320
      ],
      "id": "ead7694a-e48a-4232-8690-1a876a82d1a6",
      "name": "Normalize Input"
    },
    {
      "parameters": {
        "model": "deepseek/deepseek-v4-flash",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "typeVersion": 1,
      "position": [
        368,
        -176
      ],
      "id": "1d87a805-7026-4358-bafa-7c5eeccb4b61",
      "name": "Model 1",
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "model": "nvidia/nemotron-3-ultra-550b-a55b:free",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "typeVersion": 1,
      "position": [
        208,
        256
      ],
      "id": "c45e40c2-d343-418a-9a26-a2e1dffd2ba3",
      "name": "Analyst 1",
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "typeVersion": 1,
      "position": [
        336,
        256
      ],
      "id": "2d3355c0-783c-4b71-b009-d526b69495a5",
      "name": "Analyst2",
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "model": "openai/gpt-5.6-luna",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "typeVersion": 1,
      "position": [
        544,
        256
      ],
      "id": "4711f536-64fe-43b6-b8ba-6f899289f444",
      "name": "Searcher1",
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "model": "deepseek/deepseek-v4-flash",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "typeVersion": 1,
      "position": [
        656,
        256
      ],
      "id": "cba21537-40cf-4224-87db-8204dcf2bdd4",
      "name": "Searcher2",
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "model": "qwen/qwen3.5-flash-02-23",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "typeVersion": 1,
      "position": [
        928,
        256
      ],
      "id": "6cd573ad-52e6-4ac4-a16b-3e34bc4f5801",
      "name": "Finance1",
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "typeVersion": 1,
      "position": [
        1024,
        256
      ],
      "id": "0a9f5fbf-3069-4636-aa59-7c44a93d89d1",
      "name": "Finance2",
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "url": "https://query1.finance.yahoo.com/",
        "sendHeaders": true,
        "specifyHeaders": "json",
        "jsonHeaders": "{\n  \"headers\": {\n    \"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36\",\n    \"Accept\": \"application/json\",\n    \"Accept-Language\": \"en-US,en;q=0.9\"\n  },\n  \"sendBody\": false,\n  \"body\": {}\n}",
        "options": {
          "timeout": 10000
        }
      },
      "type": "n8n-nodes-base.httpRequestTool",
      "typeVersion": 4.4,
      "position": [
        1152,
        256
      ],
      "id": "74af3e39-45ac-4f7a-9eba-e80589d753d3",
      "name": "WebSearch2"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.tavily.com/search",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "httpBearerAuth",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "query",
              "value": "={{ $fromAI('query', 'Testo o parole chiave da cercare sul web', 'string') }}"
            },
            {
              "name": "search_depth",
              "value": "advanced"
            },
            {
              "name": "max_results",
              "value": "3"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequestTool",
      "typeVersion": 4.4,
      "position": [
        800,
        256
      ],
      "id": "cda01f0f-9e0a-46ea-ac40-8598a7546d64",
      "name": "WebSearch1",
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        },
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "editMessageText",
        "chatId": "={{ $('Normalize Input').item.json.parameters.assignments.assignments[1].value }}",
        "messageId": "={{ $('Processing Signal').first().json.result.message_id }}",
        "text": "={{ $json.response }}",
        "additionalFields": {
          "parse_mode": "HTML"
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        1104,
        -320
      ],
      "id": "1b01343c-6336-412f-b2b0-a81a351e4afd",
      "name": "Final Response",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "file",
        "fileId": "={{ $('Telegram Trigger').item.json.message.voice.file_id }}",
        "additionalFields": {
          "mimeType": "=audio/ogg"
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        160,
        -720
      ],
      "id": "d39828dd-f483-4b5f-ae73-97cc8022e9f8",
      "name": "Audio file",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const buffer = await this.helpers.getBinaryDataBuffer(0, 'data');\nconst item = $input.first();\nitem.binary.data = await this.helpers.prepareBinaryData(buffer, 'voice.ogg', 'audio/ogg');\nreturn [item];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        320,
        -720
      ],
      "id": "529c0ab4-f81f-4d34-b324-6d1361758748",
      "name": "Audio data"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "loose",
                  "version": 3
                },
                "conditions": [
                  {
                    "leftValue": "={{ $('Telegram Trigger').item.json.message.voice.file_id }}",
                    "rightValue": "",
                    "operator": {
                      "type": "string",
                      "operation": "notEmpty",
                      "singleValue": true
                    },
                    "id": "a9c45805-2bf8-499c-a6d9-e2a784ba5871"
                  }
                ],
                "combinator": "and"
              }
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "loose",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "41b32b2c-755c-4e8f-bb45-26636b501399",
                    "leftValue": "={{ $('Telegram Trigger').item.json.message.text }}",
                    "rightValue": "",
                    "operator": {
                      "type": "string",
                      "operation": "notEmpty",
                      "singleValue": true
                    }
                  }
                ],
                "combinator": "and"
              }
            }
          ]
        },
        "looseTypeValidation": "={{ true }}",
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.4,
      "position": [
        -64,
        -336
      ],
      "id": "d0fb6cd3-e24d-439e-bd66-cae4ada02241",
      "name": "Switch: Voice vs Text Input"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://host.docker.internal:8000/v1/audio/transcriptions",
        "sendBody": true,
        "contentType": "multipart-form-data",
        "bodyParameters": {
          "parameters": [
            {
              "parameterType": "formBinaryData",
              "name": "file",
              "inputDataFieldName": "data"
            },
            {
              "name": "response_format",
              "value": "json"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        160,
        -528
      ],
      "id": "6ac46b6f-0ed0-47a3-9fb4-4c8b4bff8262",
      "name": "Whisper - Transcriber"
    },
    {
      "parameters": {
        "jsCode": "const transcribedText = $json.text;\n\nreturn [\n  {\n    json: {\n      message: {\n        text: transcribedText,\n        chat: { id: $('Telegram Trigger').first().json.message.chat.id },\n        from: { first_name: $('Telegram Trigger').first().json.message.from.first_name }\n      }\n    }\n  }\n];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        320,
        -528
      ],
      "id": "15aefe70-a14a-45a7-bce3-1d3fbe374e0f",
      "name": "Converted message"
    },
    {
      "parameters": {
        "jsCode": "function extractOutput(value, depth = 0) {\n  if (depth > 5) return String(value);\n  if (typeof value === 'string') {\n    const trimmed = value.trim();\n    if (trimmed.startsWith('[') || trimmed.startsWith('{')) {\n      try {\n        return extractOutput(JSON.parse(trimmed), depth + 1);\n      } catch (e) {\n        return value;\n      }\n    }\n    return value;\n  }\n  if (Array.isArray(value)) {\n    return extractOutput(value[0], depth + 1);\n  }\n  if (value && typeof value === 'object') {\n    if (value.output !== undefined) return extractOutput(value.output, depth + 1);\n    if (value.response !== undefined) return extractOutput(value.response, depth + 1);\n    if (value.text !== undefined) return extractOutput(value.text, depth + 1);\n    if (value.content !== undefined) return extractOutput(value.content, depth + 1);\n    return JSON.stringify(value);\n  }\n  return String(value);\n}\n\nfunction stripPromptTags(text) {\n  const promptTags = ['role','context','objective','instructions','constraints','query','output_rules','output_structure','data_hierarchy','hard_rule','available_agents','formatting','ticker_resolution','metrics','direct_response'];\n  const tagPattern = new RegExp(`</?(?:${promptTags.join('|')})[^>]*>`, 'gi');\n  return text.replace(tagPattern, '');\n}\n\nfunction escapeHtml(str) {\n  return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n}\n\n// Tokenizza, HTML-esca tutto il testo (anche dentro <pre>/<code>),\n// e BILANCIA i tag: chiusure orfane scartate, tag aperti chiusi d'ufficio a fine stringa.\n// Garantisce sempre HTML Telegram valido, qualunque cosa emetta il modello.\nfunction sanitizeForTelegramHtml(text) {\n  const ALLOWED = ['b', 'i', 'code', 'pre', 'a'];\n  const TAG_RE = new RegExp(`<\\\\/?(?:${ALLOWED.join('|')})(?:\\\\s[^>]*)?>`, 'gi');\n\n  const tokens = [];\n  let last = 0;\n  let m;\n  TAG_RE.lastIndex = 0;\n  while ((m = TAG_RE.exec(text)) !== null) {\n    if (m.index > last) tokens.push({ type: 'text', value: text.slice(last, m.index) });\n    tokens.push({ type: 'tag', value: m[0] });\n    last = TAG_RE.lastIndex;\n  }\n  if (last < text.length) tokens.push({ type: 'text', value: text.slice(last) });\n\n  const out = [];\n  const stack = [];\n\n  for (const tok of tokens) {\n    if (tok.type === 'text') {\n      out.push(escapeHtml(tok.value));\n      continue;\n    }\n    const raw = tok.value;\n    const closing = /^<\\//.test(raw);\n    const name = raw.replace(/^<\\/?/, '').replace(/[\\s>].*$/, '').toLowerCase();\n\n    if (closing) {\n      const idx = stack.lastIndexOf(name);\n      if (idx === -1) continue; // chiusura orfana: scartata\n      while (stack.length - 1 > idx) out.push(`</${stack.pop()}>`); // auto-chiude interleaving errati\n      stack.pop();\n      out.push(`</${name}>`);\n    } else {\n      if (name === 'a') {\n        const href = (raw.match(/href\\s*=\\s*\"([^\"]*)\"/i) || [])[1];\n        if (!href) continue; // <a> senza href non \u00e8 valido su Telegram: scartato\n        stack.push('a');\n        out.push(`<a href=\"${href}\">`);\n      } else {\n        stack.push(name); // b/i/code/pre: attributi rimossi, forma nuda\n        out.push(`<${name}>`);\n      }\n    }\n  }\n\n  while (stack.length) out.push(`</${stack.pop()}>`); // chiude tag aperti (es. <pre> troncato)\n  return out.join('');\n}\n\nfunction cleanAgentOutput(text) {\n  if (typeof text !== 'string') return String(text);\n  let cleaned = stripPromptTags(text);\n  cleaned = cleaned.replace(/\\{\\{.*?\\}\\}/g, '');\n  cleaned = sanitizeForTelegramHtml(cleaned);\n  cleaned = cleaned.replace(/\\n{3,}/g, '\\n\\n').trim();\n  return cleaned;\n}\n\nconst rawOutput = extractOutput($input.first().json);\nconst cleanOutput = cleanAgentOutput(rawOutput);\n\nreturn [\n  {\n    json: {\n      response: cleanOutput,\n      raw: rawOutput,\n    }\n  }\n];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        880,
        -320
      ],
      "id": "02a55f89-40b9-4b9d-94f3-d60eeddcb3ab",
      "name": "Output Formatter"
    },
    {
      "parameters": {
        "toolDescription": "Executes live web searches via Tavily or SerpAPI tool node, synthesises retrieved content into a cited factual summary. The LLM here acts as an extraction and synthesis layer over raw search results ",
        "text": "=<role>\nReal-time research specialist. Always search live web data for anything time-sensitive, never rely on static memory for current events, prices, or dates.\n</role>\n\n<context>\nInput: {{ $json.parameters.assignments.assignments[0].value }}\n</context>\n\n<instructions>\nRun targeted searches, prefer sources from the last 30 days, prioritize official/major outlets. Cross-check up to 3 sources internally, never label them in the output. Answer in the user's language. Mention dates only if they change the claim's meaning. Fold contradictions into the prose only if material.\n</instructions>\n\n<formatting>\nTarget: Telegram mobile, narrow screen (~32 monospace chars usable). Pick the structure that survives a phone screen, not the one that looks good on desktop.\n- Simple factual answer: plain prose, 3-6 sentences, no structure.\n- List of distinct items/factors: bullet lines, one per line, prefix \"\u2022 \", no nesting.\n- Comparison of 2-3 entities across attributes (DEFAULT for comparisons): vertical labeled blocks. One attribute per block: <b>heading</b>, then one short line per entity marked with an emoji/flag. Never a wide table for this.\n    <b>Bev\u00f6lkerung</b>\n    \ud83c\udde9\ud83c\uddea 83,6 Mio.\n    \ud83c\uddee\ud83c\uddf9 58,9 Mio.\n- <pre> monospace table: ONLY if every cell is a short scalar (number, %, currency, \u22648 chars) AND \u22643 columns AND each line \u226432 chars. Right-align numbers, pad columns, NO emoji inside <pre>. If any cell needs prose, a table is forbidden: use labeled blocks.\n- Close a comparison with 2-3 plain-prose sentences of synthesis.\nSources: at most, bare links at the end, one per line, no labels. Omit if not needed.\nTelegram HTML only: <b> <i> <code> <pre> <a href=\"...\">. No markdown, no <table>/<ul>/<li>/<div>.\n</formatting>\n\n<constraints>\nMax 300 words. No em dashes. Blacklist: delve, tapestry, multifaceted, embark, unlocking. No preamble, start with the answer.\n</constraints>\n\n<query>{{ $json.parameters.assignments.assignments[0].value }}</query>",
        "needsFallback": true,
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.agentTool",
      "typeVersion": 3,
      "position": [
        624,
        64
      ],
      "id": "a79a7985-e462-45db-8641-2d9c823029ac",
      "name": "Agent - Web Researcher"
    },
    {
      "parameters": {
        "toolDescription": "Retrieves and processes market data via HTTP tool calls (Yahoo Finance / Alpha Vantage), computes performance metrics (weekly return, benchmark delta, Sharpe), and returns structured Telegram markdown. Data-fetching is the bottleneck, not LLM inference.",
        "text": "=<role>\nQuantitative analyst. Precision over style, never fabricate data or metrics.\n</role>\n\n<context>\nInput: {{ fromAI('query') }}\nAlways fetch live data via tools before answering. Respond in the user's language.\n</context>\n\n<ticker_resolution>\nConvert names to Yahoo Finance tickers before any tool call: S&P 500\u2192%5EGSPC, Nasdaq\u2192%5EIXIC, Dow\u2192%5EDJI, Bitcoin\u2192BTC-USD, Ethereum\u2192ETH-USD, Gold\u2192GC=F, Oil\u2192CL=F. Company names\u2192ticker (Tesla\u2192TSLA, Nvidia\u2192NVDA). If ambiguous, pick the most liquid instrument; if truly unclear, ask.\n</ticker_resolution>\n\n<data_hierarchy>\nYahoo Finance first, Alpha Vantage fallback. If both fail: state \"Dati non disponibili: [motivo]\", never estimate.\n</data_hierarchy>\n\n<metrics>\nCompute when data allows: weekly return, benchmark delta, volatility, annualized Sharpe. If asked: alpha, beta, max drawdown, correlation. Never invent unsupported metrics.\n</metrics>\n\n<formatting>\nTarget: Telegram mobile, narrow screen (~32 monospace chars usable). Pick the structure that survives a phone screen.\n- Single asset / quick number: plain prose, numbers woven into the sentence (\"NVDA +4.2% this week, +3.2 pts over the Nasdaq, Sharpe 1.8\"). No structure.\n- Distinct risk signals: bullet lines, one per line, prefix \"\u2022 \", no nesting.\n- Comparison of 2-3 assets across attributes: vertical labeled blocks. One metric per block, <b>heading</b>, one short line per asset. No wide table for prose content.\n- <pre> monospace table: the right tool for a numeric ranking/matrix, but ONLY if every cell is a short scalar (number, %, ticker, \u22648 chars) AND \u22643 columns AND each line \u226432 chars. Right-align numbers, pad columns to fixed width, NO emoji inside <pre>.\n    <pre>\n    Titolo    Sett.   vs Idx\n    NVDA     +4.2%    +3.2\n    AAPL     -1.1%    -2.1\n    </pre>\n- If any cell needs prose, a table is forbidden: use labeled blocks.\nTelegram HTML only: <b> <i> <code> <pre>. No markdown, no <table>/<ul>/<li>/<div>.\n</formatting>\n\n<constraints>\nNo forecasts, no investment advice, no speculative language. Max 200 words unless a numeric table is genuinely needed. No em dashes. Blacklist: delve, tapestry, multifaceted, comprehensive, unlocking, transformative. No preamble, start with the answer.\n</constraints>\n\n<query>\n{{ fromAI('query') }}\n</query>",
        "needsFallback": true,
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.agentTool",
      "typeVersion": 3,
      "position": [
        944,
        64
      ],
      "id": "3fc7f053-fd17-431f-96fa-4186df7ea493",
      "name": "Agent - Finance Analyst"
    },
    {
      "parameters": {
        "toolDescription": "Accepts quantitative or code-generation requests, produces executable Python/JS blocks with minimal commentary, and optionally pipes output through n8n's Code Node for immediate execution.",
        "text": "=<role>\nGeneral-purpose reasoning and code assistant. Handles calculations, logic, code generation/review, and organizing notes. No live data access, no persistent storage: if asked to set a reminder or save something, say clearly you can't persist it beyond this chat and return the info as text instead.\n</role>\n\n<context>\nInput: {{ fromAI('query') }}\nRespond in the user's language.\n</context>\n\n<instructions>\nCode: clean, minimal, runnable Python or JS. Comment only non-obvious lines. No preamble.\nCalculations/logic: show steps only if they aid understanding.\nNotes/organization: structure only as much as the content needs.\nNever fabricate facts or data you don't have.\n</instructions>\n\n<formatting>\nTarget: Telegram mobile, narrow screen (~32 monospace chars usable for data tables).\n- Prose answer: plain text, no structure.\n- Distinct items: bullet lines, one per line, prefix \"\u2022 \", no nesting.\n- Code: always inside <pre>. The ~32-char width limit does NOT apply to code, horizontal scroll is acceptable for code blocks. Keep original indentation.\n- Comparison of 2-3 entities: vertical labeled blocks (<b>heading</b> + one short line per entity). No wide prose tables.\n- Data table in <pre>: ONLY short scalar cells, \u22643 columns, \u226432 chars/line, no emoji inside <pre>.\nTelegram HTML only: <b> <i> <code> <pre>. No markdown, no <table>/<ul>/<li>/<div>.\n</formatting>\n\n<constraints>\nMax 200 words unless code genuinely needs more. No em dashes. Blacklist: delve, tapestry, multifaceted, comprehensive, unlocking, transformative. No preamble, start with the answer.\n</constraints>\n\n<query>\n{{ fromAI('query') }}\n</query>",
        "needsFallback": true,
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.agentTool",
      "typeVersion": 3,
      "position": [
        304,
        64
      ],
      "id": "4f4de8fa-5907-4771-b9dc-c28490fa0674",
      "name": "Agent - Data & Coding Analyst"
    },
    {
      "parameters": {
        "chatId": "={{ $json.message.chat.id }}",
        "text": "\u23f3 Sto elaborando la risposta...",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        -416,
        -336
      ],
      "id": "86854fe3-2fb5-4d82-8d0e-185b64cf1199",
      "name": "Processing Signal",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=<role>\nAct as a Senior Metacognitive Orchestrator for a multi-agent system. Your job is precise intent classification and mandatory delegation to exactly one sub-agent. You answer directly ONLY for trivial DIRECT_RESPONSE cases.\n</role>\n\n<context>\nInput: {{ $json.parameters.assignments.assignments[0].value }}\nClassify the message, then either answer directly (DIRECT_RESPONSE only) or delegate to exactly one specialized sub-agent tool.\n\nAvailable agents:\n1. FINANCE_AGENT: ETFs, stocks, portfolio analysis, market data, finance.\n2. WEB_RESEARCHER: factual research, news, recipes, summaries, web lookups.\n3. DATA_ANALYST: calculations, code generation/review, logic, organizing notes.\n</context>\n\n<direct_response>\nDIRECT_RESPONSE is for messages needing no external data, computation, or specialized reasoning:\n- greetings and social pleasantries (hi, thanks, how are you)\n- meta-questions about the bot (what can you do, who are you)\n- acknowledgments and conversation closers\n- basic static facts (e.g. \"12*7\", \"capital of France\")\nIf there is ANY ambiguity about whether specialized data or reasoning is needed, delegate. DIRECT_RESPONSE is the exception, not the default.\n</direct_response>\n\n<instructions>\nReason internally in three phases:\n1. Intent Analysis: map the primary intent to exactly one agent.\n2. Parameter Extraction: pull the entities the selected agent needs.\n3. Delegation: invoke that single agent tool with the processed query. Forward the request unchanged unless minimal clarification is strictly necessary.\n</instructions>\n\n<constraints>\n- DIRECT_RESPONSE: answer directly, concise, in the user's language. Telegram HTML only (<b> <i> <code>), no markdown, no preamble.\n- Delegated cases: call exactly one agent tool, never zero, never two. When a tool returns, output its result VERBATIM: do not reformat, re-summarize, wrap, or add commentary. The sub-agent output is the final answer.\n- Never produce a standalone answer for non-trivial queries.\n- No em dashes, prefer colons or commas. Blacklist: delve, tapestry, comprehensive.\n</constraints>\n\n<query>\n{{ $json.parameters.assignments.assignments[0].value }}\n</query>\n",
        "needsFallback": true,
        "options": {
          "maxIterations": 10
        }
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3.1,
      "position": [
        528,
        -320
      ],
      "id": "cfe211a5-1a43-44af-9d69-0ee3ae0c8543",
      "name": "AI Orchestrator"
    },
    {
      "parameters": {
        "operation": "sendChatAction",
        "chatId": "={{ $('Telegram Trigger').item.json.message.chat.id }}"
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        -240,
        -336
      ],
      "id": "da2e62fd-7c78-4d2b-9cfc-204d8474f20e",
      "name": "Typing Indicator",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "type": "n8n-nodes-base.telegramTrigger",
      "typeVersion": 1.3,
      "position": [
        -592,
        -336
      ],
      "id": "ad85571b-f7ab-4681-955e-209bd78dcd39",
      "name": "Telegram Trigger",
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Fallback": {
      "ai_languageModel": [
        [
          {
            "node": "AI Orchestrator",
            "type": "ai_languageModel",
            "index": 1
          }
        ]
      ]
    },
    "Normalize Input": {
      "main": [
        [
          {
            "node": "AI Orchestrator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Model 1": {
      "ai_languageModel": [
        [
          {
            "node": "AI Orchestrator",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Analyst 1": {
      "ai_languageModel": [
        [
          {
            "node": "Agent - Data & Coding Analyst",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Analyst2": {
      "ai_languageModel": [
        [
          {
            "node": "Agent - Data & Coding Analyst",
            "type": "ai_languageModel",
            "index": 1
          }
        ]
      ]
    },
    "Searcher1": {
      "ai_languageModel": [
        [
          {
            "node": "Agent - Web Researcher",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Searcher2": {
      "ai_languageModel": [
        [
          {
            "node": "Agent - Web Researcher",
            "type": "ai_languageModel",
            "index": 1
          }
        ]
      ]
    },
    "Finance1": {
      "ai_languageModel": [
        [
          {
            "node": "Agent - Finance Analyst",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Finance2": {
      "ai_languageModel": [
        [
          {
            "node": "Agent - Finance Analyst",
            "type": "ai_languageModel",
            "index": 1
          }
        ]
      ]
    },
    "WebSearch2": {
      "ai_tool": [
        [
          {
            "node": "Agent - Finance Analyst",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "WebSearch1": {
      "ai_tool": [
        [
          {
            "node": "Agent - Web Researcher",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Audio file": {
      "main": [
        [
          {
            "node": "Audio data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Audio data": {
      "main": [
        [
          {
            "node": "Whisper - Transcriber",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch: Voice vs Text Input": {
      "main": [
        [
          {
            "node": "Audio file",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Normalize Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Whisper - Transcriber": {
      "main": [
        [
          {
            "node": "Converted message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Converted message": {
      "main": [
        [
          {
            "node": "Normalize Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Output Formatter": {
      "main": [
        [
          {
            "node": "Final Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Agent - Web Researcher": {
      "ai_tool": [
        [
          {
            "node": "AI Orchestrator",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Agent - Finance Analyst": {
      "ai_tool": [
        [
          {
            "node": "AI Orchestrator",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Agent - Data & Coding Analyst": {
      "ai_tool": [
        [
          {
            "node": "AI Orchestrator",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Processing Signal": {
      "main": [
        [
          {
            "node": "Typing Indicator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Orchestrator": {
      "main": [
        [
          {
            "node": "Output Formatter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Typing Indicator": {
      "main": [
        [
          {
            "node": "Switch: Voice vs Text Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Telegram Trigger": {
      "main": [
        [
          {
            "node": "Processing Signal",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate"
  },
  "versionId": "a3155b90-8082-49c1-977c-25b85ad5eded",
  "id": "aV5Bq1O1PEzuMiYl",
  "tags": []
}