{
  "id": "0bFdNKsZNQQP195l",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Telegram Personal Expense Tracker Agent",
  "tags": [],
  "nodes": [
    {
      "id": "b591a5c7-e6f3-4a29-b73f-93ebee2c031a",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1968,
        912
      ],
      "parameters": {
        "color": 7,
        "width": 208,
        "height": 304,
        "content": "## Message Trigger"
      },
      "typeVersion": 1
    },
    {
      "id": "e5edd200-825e-4da0-b807-6f153acfed6c",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2448,
        480
      ],
      "parameters": {
        "width": 688,
        "height": 1472,
        "content": "# Personal Expense Tracker \n## Quick Start Guide\n## 1. Setup Telegram\n### 1.1 Create Telegram Bot\n - https://blog.n8n.io/create-telegram-bot/\n### 1.2 Setup Telegram Credentials for each Telegram Node: \n - Input\n - WelcomeMessage\n - GetAudioFile\n - GetAttachedFile\n - GetAttachedPhoto\n - ReplyText\n - NotAuthorizedMessage\n - DeleteProcessing\n\n## 2. Setup OpenRouter\n### 2.1 Create API Key\n - https://docs.n8n.io/integrations/builtin/credentials/openrouter/\n### 2.2 Setup AI Credentials for each AI Node: \n - Gpt4o\n - Sonnet45\n\n## 3. Setup Ainoflow\n### 3.1 Create API Key\n - https://www.ainoflow.io/signup\n### 3.2 Setup Bearer YOUR_TOKEN_HERE for each Ainoflow Node: \n - GetAppSettings\n - SaveAppSettings\n - SaveExecutionState\n - TranscribeAudio\n - ExtractFileText\n - ExtractImageText\n - TranscribeRecording\n - GetExecutionState\n - ForEachCategory\n - ForEachCategoryItem\n - DeleteItem\n### 3.3 Setup Bearer YOUR_TOKEN_HERE for MCP Tools\n - JsonStorageMcp\n\n## 4. How to use Bot\n### 4.1. Upload expense information\n - Invoice PDF\n - Image Photo\n - Any text about expense\n### 4.2. Write / Voice Chat about any additional expense\n### 4.3. Ask `Get my expenses`\n - Get by category\n - Get for previous month\n - Get for current month\n - Discuss habits\n - Ask to provide link to expense file (if available)\n\n## 5. Need customization? \n - Contact me via https://ainovasystems.com/"
      },
      "typeVersion": 1
    },
    {
      "id": "40ad1d9c-484a-44f5-9428-80696c6f65a1",
      "name": "Trigger",
      "type": "n8n-nodes-base.telegramTrigger",
      "position": [
        -1920,
        1024
      ],
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {
          "chatIds": "",
          "userIds": "",
          "download": true,
          "imageSize": "extraLarge"
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "7501af4e-cb14-47b8-ba5b-f91389a0c6a2",
      "name": "JsonStorageMcp",
      "type": "@n8n/n8n-nodes-langchain.mcpClientTool",
      "position": [
        96,
        1744
      ],
      "parameters": {
        "options": {},
        "endpointUrl": "https://mcp.ainoflow.io/mcp/v1/storage/json",
        "authentication": "bearerAuth",
        "serverTransport": "httpStreamable"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "ff3d434c-68ec-4ff6-a790-34cbc65ee2c4",
      "name": "Calculator",
      "type": "@n8n/n8n-nodes-langchain.toolCalculator",
      "position": [
        352,
        1744
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "fc175bad-072b-4740-b463-08ee226383f7",
      "name": "ExpenseAssistant",
      "type": "@n8n/n8n-nodes-langchain.agentTool",
      "position": [
        -80,
        1520
      ],
      "parameters": {
        "text": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Prompt__User_Message_', ``, 'string') }}",
        "options": {
          "systemMessage": "=# Expense Manager\n\n## Role\nYou manage expense recording and retrieval. You extract expense data from text or OCR, validate it, store it using MCP tools, and provide expense information.\n\n## Available MCP Tools\n\nJsonStorageMcp:\n- storage_json_create(category, data, expiresAt?, expiresMs?) - create with auto-generated key\n- storage_json_upsert(category, key, data, expiresAt?, expiresMs?) - create/update with explicit key\n- storage_json_get(category, key) - retrieve data\n- storage_json_delete(category, key) - delete data\n- storage_json_list_keys(category, page?, limit?) - list all keys in category\n\nCalculator:\n- Performs sums, averages, percentages\n\n## Allowed Expense Categories\n\nCRITICAL: Use ONLY these categories. If category not specified or unclear, use \"Other\".\n\nGroceries, Transportation, Housing, Utilities, Healthcare, Entertainment, Dining Out, Clothing, Education, Subscriptions, Personal Care, Gifts, Travel, Sports, Other\n\n## Data Storage Structure\n\nCategory in JSON Storage: YYYY-MM (year-month from expense date)\nRecord key: auto-generated by storage_json_create\n\nExpense record format:\n```json\n{\n  \"id\": \"uuid\",\n  \"amount\": 45.50,\n  \"currency\": \"EUR\",\n  \"category\": \"Groceries\",\n  \"description\": \"Store name or purchase description\",\n  \"date\": \"2025-11-10T14:30:00Z\",\n  \"created_at\": \"2025-11-10T14:35:22Z\"\n}\n```\n\nRequired fields: id, amount (>0), currency, category (from allowed list), date, created_at\nOptional fields: description (in original document language)\n\n## Operations\n\n### 1. Add Expense\n\nCRITICAL: Add immediately without asking confirmation\n\nStep 1: Extract expense data\n- Extract amount, category, description, date, currency from text or OCR\n- If cannot extract amount \u2192 stop, inform user\n\nStep 2: Validate\n- amount > 0, category from allowed list, date valid\n- If data invalid \u2192 stop, explain the problem\n\nStep 3: Create expense\n- Generate UUID for id field\n- Call: storage_json_create(category=\"YYYY-MM\", data=expense_json)\n\nStep 4: Format response\n- Show: \"Added: *{amount} {currency}* - {category} ({description})\"\n- Show: \"Monthly total: *{total} {currency}* ({count} expenses)\"\n\nNEVER ask \"Please confirm\", \"Is this correct?\", or any confirmation questions.\n\nIf failed to extract expense:\n- \"Cannot find amount in document. Please specify amount manually.\"\n- \"Document does not contain expense information. Send a receipt or describe expense in text.\"\n\n### 2. Get Monthly Expenses\n\nDetermine period (YYYY-MM) - if not specified by user, use current month\nCall: storage_json_list_keys(category=\"YYYY-MM\")\nFor each key call: storage_json_get(category, key)\nUse Calculator for total and count\nShow summary with top expenses if many\n\n### 3. Get Expenses by Category\n\nValidate category from allowed list\nDetermine period (YYYY-MM or range) - if not specified, use current month\nGet all expenses for period\nFilter by category field\nUse Calculator for statistics\nShow results\n\n### 4. Multi-Month Statistics\n\nDetermine date range\nFor each month: storage_json_list_keys + storage_json_get\nUse Calculator for comparative statistics\nShow breakdown by months and categories\n\n### 5. Delete Expense\n\nFind expense by description/amount/date\nGet expense details\nAsk confirmation\nCall: storage_json_delete(category=\"YYYY-MM\", key)\nShow updated monthly total\n\n## Input Processing\n\n### Input Format\n\nYou ALWAYS receive text input. There are two formats:\n\n**1. Direct text from user:**\n```\nspent 50 on groceries\n```\nor just amount: \"45.50\"\nor transcribed voice: \"bought bread for 3 euros\"\n\n**2. Uploaded document/photo (prefixed format):**\n```\nUser uploaded document / photo:\n\n[optional caption from user]\n[extracted text from document/image OR error message]\n```\n\nWhen message starts with \"User uploaded document / photo:\":\n- If text is \"The uploaded file does not contain text content.\" \u2192 respond: \"Could not recognize text. Try:\\n- Upload higher quality photo\\n- Send PDF\\n- Write expense as text\"\n- Otherwise: CRITICAL! This is expense data! The text after prefix is OCR from receipt/photo or extracted text from PDF invoice. Process it and extract expense.\n\n### Data Extraction Rules\n\nFor all input:\n- Extract final total amount (after taxes/discounts)\n- Recognize date in any format, convert to ISO 8601\n- Determine category from context or vendor type\n- Create clear description from available information\n- Default currency EUR if not specified\n- Add immediately and show what was saved\n- Process content in ANY language (Russian, English, Portuguese, etc.)\n\n## Important Rules\n\nAdd expenses immediately when user provides data (text, OCR, invoice)\nVerify after action - retrieve data and confirm saved correctly\nAsk confirmation ONLY for DELETE operations\nStore in correct YYYY-MM category based on expense date\nUse Calculator for totals and statistics\nHandle any text format, date format, or currency flexibly\nDon't show technical details (storage keys, API calls) to user\n\nError handling:\n- If cannot extract amount from document \u2192 inform user clearly\n- If document doesn't contain expense \u2192 suggest solution\n- If data invalid \u2192 explain what's wrong\n- DO NOT add expense with incomplete data\n\nMultilingual:\n- Process documents and messages in ANY language\n- Keep description in original language\n- Always translate category to English (from allowed list)\n- Recognize currency names in any language\n\nFormatting:\n- Use Legacy Telegram markdown: *bold* (SINGLE asterisk) for amounts\n- NEVER use ** (double asterisk) or __ (double underscore)\n- Keep responses concise and clean\n- Don't use bullet points in responses unless user specifically asks\n\nCurrent date/time: {{ $now.toISO() }}\nCurrent storage category: {{ $now.toFormat('yyyy-MM') }}\nDefault currency: EUR\n"
        },
        "toolDescription": "AI Assitante can handle expense recording and retrieval operations."
      },
      "typeVersion": 2.2
    },
    {
      "id": "b0269ed8-4f74-4a09-ac95-ecbec2c4fd91",
      "name": "Gpt4o",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        -160,
        1248
      ],
      "parameters": {
        "model": "openai/gpt-4o",
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "c2aad759-3504-48e4-833a-771398ff586a",
      "name": "Think",
      "type": "@n8n/n8n-nodes-langchain.toolThink",
      "position": [
        224,
        1744
      ],
      "parameters": {},
      "typeVersion": 1.1
    },
    {
      "id": "89a37291-a019-488c-9ada-604f5460d638",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "disabled": true,
      "position": [
        -1184,
        912
      ],
      "parameters": {
        "color": 2,
        "width": 960,
        "height": 400,
        "content": "## Get Chat Message / Audio Text\nDetect message type (/start, text, photo, file, audio) and route to the correct handler. \nText and audio messages are passed to the AI agent as-is.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "c245ce07-5c27-4096-8f16-85c3766a285d",
      "name": "Switch",
      "type": "n8n-nodes-base.switch",
      "position": [
        -1136,
        1024
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "start",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "2061a135-7380-4108-b565-99ebc16ac37f",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $('Trigger').item.json.message.text }}",
                    "rightValue": "/start"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "text",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "665a9274-2939-4069-ad27-02556447d7d3",
                    "operator": {
                      "type": "string",
                      "operation": "exists",
                      "singleValue": true
                    },
                    "leftValue": "={{ $('Trigger').item.json.message.text }}",
                    "rightValue": ""
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "audio",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "d7360abd-5fce-4f60-832a-b7fb405255ee",
                    "operator": {
                      "type": "string",
                      "operation": "exists",
                      "singleValue": true
                    },
                    "leftValue": "={{ $('Trigger').item.json.message.voice.file_id }}",
                    "rightValue": ""
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "file",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "fa626c9d-b758-492b-ae44-fb6866763558",
                    "operator": {
                      "type": "string",
                      "operation": "exists",
                      "singleValue": true
                    },
                    "leftValue": "={{ $('Trigger').item.json.message.document.file_id }}",
                    "rightValue": ""
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "photo",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "194e3899-6a63-46db-a826-ad2768390ec5",
                    "operator": {
                      "type": "array",
                      "operation": "exists",
                      "singleValue": true
                    },
                    "leftValue": "={{ $('Trigger').item.json.message.photo }}",
                    "rightValue": "photo"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.3
    },
    {
      "id": "197310fd-2237-414a-84a0-ec7e2fada7b3",
      "name": "TextOutput",
      "type": "n8n-nodes-base.set",
      "position": [
        -592,
        976
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "2ee0477d-52cd-4050-86d4-5cef92b81ea8",
              "name": "text",
              "type": "string",
              "value": "={{ $('Trigger').item.json.message.text }}"
            },
            {
              "id": "65245fe2-4dd7-4330-974b-4a0fdbbd93a4",
              "name": "chat_id",
              "type": "string",
              "value": "={{ $('Trigger').item.json.message.chat.id }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "ab6e3624-de0d-4043-ba72-3e62ee120d01",
      "name": "WelcomeMessage",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -544,
        736
      ],
      "parameters": {
        "text": "=Hi! I'm your personal expense tracker.\n\nSend me an expense in any format, and I'll save it automatically:\n- \ud83d\udcdd Text: \"spent 50 on groceries\"\n- \ud83d\udcf7 Receipt photo\n- \ud83d\udcc4 PDF invoice\n- \ud83c\udfa4 Voice: \"bought bread for 3 euros\"\n\nI'll organize everything by months and categories.\n\nAsk me anytime:\n- \"How much this month?\"\n- \"Show grocery expenses\"\n- \"Compare last 3 months\"\n\nReady to track your first expense?",
        "chatId": "={{ $('Trigger').item.json.message.chat.id }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "7c9b6743-39ec-4195-8792-dff233a859b1",
      "name": "AudioOutput",
      "type": "n8n-nodes-base.set",
      "position": [
        -592,
        1136
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "2ee0477d-52cd-4050-86d4-5cef92b81ea8",
              "name": "text",
              "type": "string",
              "value": "={{ $json.content[0].text }}"
            },
            {
              "id": "dde56955-afe3-4858-bc1b-bbca9a87ee65",
              "name": "chat_id",
              "type": "string",
              "value": "={{ $('Trigger').item.json.message.chat.id }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "35cd08cb-7dc2-4a5c-9454-47a9f9ce8dac",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "disabled": true,
      "position": [
        224,
        912
      ],
      "parameters": {
        "color": 4,
        "width": 288,
        "height": 480,
        "content": "## Result / Reply Message\nSends reply to the user"
      },
      "typeVersion": 1
    },
    {
      "id": "c2ce80fa-f214-4dcc-a9bc-e182000d5125",
      "name": "AgentInput",
      "type": "n8n-nodes-base.set",
      "position": [
        -352,
        1056
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "10b3fa10-e52d-4e80-b755-0c8310f391f3",
              "name": "text",
              "type": "string",
              "value": "={{ $json.text }}"
            },
            {
              "id": "72a11c20-6ba3-42a7-9a01-1a032f16e2c6",
              "name": "chat_id",
              "type": "string",
              "value": "={{ $json.chat_id }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "3db36880-18d1-408b-bcbf-a3578e471535",
      "name": "NotAuthorizedMessage",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -1392,
        1248
      ],
      "parameters": {
        "text": "=You are not authorized to use this bot.",
        "chatId": "={{ $('Trigger').item.json.message.chat.id }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "a4f01f8a-1317-4b4c-b447-e398702c6abf",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1760,
        912
      ],
      "parameters": {
        "color": 2,
        "width": 576,
        "height": 496,
        "content": "## Ensure Bot Privacy\nOn first use, the bot stores the user ID and locks access to that user. Any other user will receive an \u201cunauthorized\u201d message.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "17330fc2-6492-4e95-a07c-f7c6778ec66a",
      "name": "IfAccessAllowed",
      "type": "n8n-nodes-base.if",
      "position": [
        -1376,
        1024
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "e3cd7b5c-eb77-451d-90a1-836353e32ab1",
              "operator": {
                "type": "number",
                "operation": "equals"
              },
              "leftValue": "={{ $('Trigger').item.json.message.chat.id }}",
              "rightValue": "={{ $json.chat_id ?? $('Trigger').item.json.message.chat.id }}"
            },
            {
              "id": "61708b93-6439-4ef4-a08c-d997f6777033",
              "operator": {
                "type": "number",
                "operation": "equals"
              },
              "leftValue": "={{ $json.error.status }}",
              "rightValue": 404
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "4ef7ad67-59c1-4dce-87e5-098da8cbdccc",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "disabled": true,
      "position": [
        -624,
        656
      ],
      "parameters": {
        "color": 4,
        "width": 400,
        "height": 256,
        "content": "## Start Message Reply\nSend user welcome message (first use)"
      },
      "typeVersion": 1
    },
    {
      "id": "f883ad91-ce2b-4cca-a90d-901633cbba0f",
      "name": "IfFirstRun",
      "type": "n8n-nodes-base.if",
      "position": [
        -1712,
        1504
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "61708b93-6439-4ef4-a08c-d997f6777033",
              "operator": {
                "type": "number",
                "operation": "equals"
              },
              "leftValue": "={{ $json.error.status }}",
              "rightValue": 404
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "7de993d2-81c0-4543-93b2-4d8453c608d1",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "disabled": true,
      "position": [
        -1760,
        1408
      ],
      "parameters": {
        "color": 4,
        "width": 576,
        "height": 288,
        "content": "## First Run - Save Config\nOn first use remember user chat_id to enable authorization check in future"
      },
      "typeVersion": 1
    },
    {
      "id": "7a9d43ec-7b81-4c8e-9222-6dd190645516",
      "name": "ReplyText",
      "type": "n8n-nodes-base.telegram",
      "position": [
        288,
        1056
      ],
      "parameters": {
        "text": "={{ $json.output }}",
        "chatId": "={{ $('AgentInput').item.json.chat_id }}",
        "additionalFields": {
          "parse_mode": "Markdown",
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "eaf63cad-d3a8-4e15-afcf-9a77e52b0b76",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "disabled": true,
      "position": [
        -1184,
        1312
      ],
      "parameters": {
        "color": 2,
        "width": 960,
        "height": 384,
        "content": "## Get Document / Photo Text\nFor photo / file upload get file content and forward to agent with appropriate prefix to make it clear that content is coming from attached file.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "99cd1c7f-0e34-47f5-8245-91410420cf6a",
      "name": "FileOutput",
      "type": "n8n-nodes-base.set",
      "position": [
        -592,
        1408
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "2ee0477d-52cd-4050-86d4-5cef92b81ea8",
              "name": "text",
              "type": "string",
              "value": "=User uploaded document / photo:\n\n{{ $('Input').item.json.message.caption ?? \"\" }}\n{{ $json.content ? $json.content[0].text : \"The uploaded file does not contain text content.\" }}"
            },
            {
              "id": "dde56955-afe3-4858-bc1b-bbca9a87ee65",
              "name": "chat_id",
              "type": "string",
              "value": "={{ $('Trigger').item.json.message.chat.id }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "a8d8281f-20d8-4039-9977-240372e8af46",
      "name": "GetAudioFile",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -880,
        1136
      ],
      "parameters": {
        "fileId": "={{ $('Trigger').item.json.message.voice.file_id }}",
        "resource": "file",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "ab30a917-2a51-4683-889a-dcb83b99e47d",
      "name": "ExtractFileText",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        -736,
        1408
      ],
      "parameters": {
        "url": "https://api.ainoflow.io/api/v1/convert/submit-file",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "multipart-form-data",
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "languages",
              "value": "={{ $('Input').item.json.document_language }}"
            },
            {
              "name": "outputs",
              "value": "text"
            },
            {
              "name": "response",
              "value": "direct"
            },
            {
              "name": "file",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "data"
            }
          ]
        },
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "alwaysOutputData": true
    },
    {
      "id": "b7f8abf7-8a0a-4737-8ebf-bed1493b4cb1",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "disabled": true,
      "position": [
        -224,
        912
      ],
      "parameters": {
        "color": 5,
        "width": 448,
        "height": 480,
        "content": "## Root Agent Processing\nMain agent responsible to forward messages to expense assistant, validate response, reject irrelevant topics, in future can be extended with more assistant connections"
      },
      "typeVersion": 1
    },
    {
      "id": "a8a31b8b-09fc-4757-90ca-050d6ce6b90d",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "disabled": true,
      "position": [
        -224,
        1392
      ],
      "parameters": {
        "color": 5,
        "width": 736,
        "height": 560,
        "content": "## Expense Assistant\nExpense assistant - handles the core logic about expenses, uses storage, calculator tools to process request"
      },
      "typeVersion": 1
    },
    {
      "id": "3dd328b8-b601-4ff8-a3ee-aa09295aa872",
      "name": "AssitantMemory",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        -48,
        1744
      ],
      "parameters": {
        "sessionKey": "=expense_assitant_{{ $('AgentInput').item.json.chat_id }}",
        "sessionIdType": "customKey"
      },
      "typeVersion": 1.3
    },
    {
      "id": "0a183256-83ac-4e0c-9173-0affc14a6368",
      "name": "SimpleMemory",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        -64,
        1248
      ],
      "parameters": {
        "sessionKey": "=agent_{{ $('AgentInput').item.json.chat_id }}",
        "sessionIdType": "customKey",
        "contextWindowLength": 30
      },
      "typeVersion": 1.3
    },
    {
      "id": "a304ae46-8c14-423b-8ebd-3ef4ad1156d6",
      "name": "AIAgent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -160,
        1056
      ],
      "parameters": {
        "text": "={{ $('AgentInput').item.json.text }}",
        "options": {
          "systemMessage": "=# Personal Expense Tracker\n\nYou DO NOT work with expenses directly. You call ExpenseAssistant for ALL expense requests.\n\n## Single Task\n\n1. Receive user message\n2. Pass to ExpenseAssistant WITHOUT modification\n3. Return its response\n\nCRITICAL: DO NOT extract amounts, do not reformat, do not summarize. Pass as-is.\n\n## When to Call ExpenseAssistant\n\nALWAYS call ExpenseAssistant for:\n- Any mention of spending, money, expenses\n- \"how much\", \"show\", \"expenses\"\n- ANY message starting with \"User uploaded document / photo:\" (regardless of content!)\n- Any text containing invoices, receipts, bills\n- Any numbers with currencies (EUR, USD, etc.)\n- Messages about \"does not contain text content\" or \"could not recognize\"\n\nCRITICAL: If you see \"User uploaded document / photo:\" \u2192 ALWAYS pass to ExpenseAssistant, even if there's an error!\n\n## For Non-Relevant Questions\n\n\"I'm an expense tracking assistant. I can add an expense or show statistics.\"\n\nDO NOT use this response for messages about uploaded documents!\n\n---\n\nCurrent date: {{ $now.toISO() }}  \nMonth: {{ $now.toFormat('yyyy-MM') }}  \nCurrency: EUR\n"
        },
        "promptType": "define"
      },
      "typeVersion": 2.2
    },
    {
      "id": "528c64fe-cb38-40c0-b847-149ec391e413",
      "name": "TranscribeAudio",
      "type": "n8n-nodes-base.httpRequest",
      "maxTries": 2,
      "position": [
        -736,
        1136
      ],
      "parameters": {
        "url": "https://api.ainoflow.io/api/v1/convert/submit-file",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "multipart-form-data",
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "languages",
              "value": "={{ $('Input').item.json.document_language }}"
            },
            {
              "name": "outputs",
              "value": "text"
            },
            {
              "name": "response",
              "value": "direct"
            },
            {
              "name": "file",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "data"
            }
          ]
        },
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.2
    },
    {
      "id": "529f8d23-31c2-41d6-a721-a8a2760003c6",
      "name": "Input",
      "type": "n8n-nodes-base.set",
      "position": [
        -1728,
        1024
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "3897ff73-577e-4e30-96bd-c043f3bc6c61",
              "name": "document_language",
              "type": "string",
              "value": "={{ $json.message.from.language_code ?? \"en\" }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "f7a90943-7f8e-45e5-917c-0d2a8c5acc74",
      "name": "GetAttachedFile",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -880,
        1408
      ],
      "parameters": {
        "fileId": "={{ $('Trigger').item.json.message.document.file_id }}",
        "resource": "file",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "af85b4d7-23ee-44e8-9ae1-77c443808701",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "disabled": true,
      "position": [
        -1184,
        656
      ],
      "parameters": {
        "color": 4,
        "width": 560,
        "height": 256,
        "content": "## Add processing started message\nNotify user about processing start (with message ... )"
      },
      "typeVersion": 1
    },
    {
      "id": "3472eaa5-12ef-41c6-9562-2c430ebb0332",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "disabled": true,
      "position": [
        -880,
        1696
      ],
      "parameters": {
        "color": 4,
        "width": 656,
        "height": 256,
        "content": "## Remove processing message\nAfter processing is complete, this part deletes temporary \"processing\" (\"...\") message"
      },
      "typeVersion": 1
    },
    {
      "id": "3be5a7aa-b70e-4143-af04-cf0b3984ba36",
      "name": "IfStateExist",
      "type": "n8n-nodes-base.if",
      "position": [
        -624,
        1792
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "c5e9f88f-3726-43a4-9394-7b2b0a95b544",
              "operator": {
                "type": "number",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.chat_id }}",
              "rightValue": ""
            },
            {
              "id": "24d6e488-9735-49bb-af52-a84fcbfbde8c",
              "operator": {
                "type": "number",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.message_id }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "96232073-4006-42f3-b19b-9ce30853f1f9",
      "name": "DeleteProcessing",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -384,
        1792
      ],
      "parameters": {
        "chatId": "={{ $json.chat_id }}",
        "messageId": "={{ $json.message_id }}",
        "operation": "deleteMessage"
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "8d890581-cfe2-4b0e-b6ee-732978b0d697",
      "name": "Think1",
      "type": "@n8n/n8n-nodes-langchain.toolThink",
      "position": [
        48,
        1248
      ],
      "parameters": {},
      "typeVersion": 1.1
    },
    {
      "id": "aef6541d-fcde-49e8-80af-63f23509bdbe",
      "name": "Cleanup",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -1696,
        1792
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "f57b4394-872c-44a0-96e9-c2990ec22447",
      "name": "ForEachCategory",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        -1504,
        1792
      ],
      "parameters": {
        "url": "https://api.ainoflow.io/api/v1/storage/json",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "alwaysOutputData": false
    },
    {
      "id": "0077379d-2fda-451e-8b6c-1d8045d8c2db",
      "name": "ForEachCategoryItem",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        -1296,
        1792
      ],
      "parameters": {
        "url": "=https://api.ainoflow.io/api/v1/storage/json/{{ $json.category }}",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "alwaysOutputData": false
    },
    {
      "id": "e09b5aa4-e64d-415b-8e18-f08aa005a98c",
      "name": "DeleteItem",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        -1072,
        1792
      ],
      "parameters": {
        "url": "=https://api.ainoflow.io/api/v1/storage/json/{{ $json.category }}/{{ $json.key }}",
        "method": "DELETE",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "alwaysOutputData": false
    },
    {
      "id": "73a49d7e-ae53-4dfb-863a-e696b1c95485",
      "name": "GetAttachedPhoto",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -880,
        1536
      ],
      "parameters": {
        "fileId": "={{ $('Trigger').item.json.message.photo[$('Trigger').item.json.message.photo.length-1].file_id }}",
        "resource": "file",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "a1fc3d64-ddf8-402c-b60f-a9e022f2f17d",
      "name": "ImageOutput",
      "type": "n8n-nodes-base.set",
      "position": [
        -592,
        1536
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "2ee0477d-52cd-4050-86d4-5cef92b81ea8",
              "name": "text",
              "type": "string",
              "value": "=User uploaded document / photo:\n\n{{ $('Input').item.json.message.caption ?? \"\" }}\n{{ $json.content ? $json.content[0].text : \"The uploaded file does not contain text content.\" }}"
            },
            {
              "id": "dde56955-afe3-4858-bc1b-bbca9a87ee65",
              "name": "chat_id",
              "type": "string",
              "value": "={{ $('Trigger').item.json.message.chat.id }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "9e7fa633-a3d5-4de1-b8b7-f056090069bf",
      "name": "Sticky Note12",
      "type": "n8n-nodes-base.stickyNote",
      "disabled": true,
      "position": [
        -1760,
        1696
      ],
      "parameters": {
        "color": 7,
        "width": 880,
        "height": 256,
        "content": "## Cleanup / Reset\nThis is **MANUAL** trigger to full data cleanup. **Warning - this will DELETE ALL DATA** stored in your **Ainoflow** account"
      },
      "typeVersion": 1
    },
    {
      "id": "424964de-61df-4f24-97a4-ae6f5d74b478",
      "name": "ExtractImageText",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        -736,
        1536
      ],
      "parameters": {
        "url": "https://api.ainoflow.io/api/v1/convert/submit-file",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "multipart-form-data",
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "languages",
              "value": "={{ $('Input').item.json.document_language }}"
            },
            {
              "name": "outputs",
              "value": "text"
            },
            {
              "name": "response",
              "value": "direct"
            },
            {
              "name": "file",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "data"
            },
            {
              "name": "models",
              "value": "paddleocr"
            }
          ]
        },
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "alwaysOutputData": true
    },
    {
      "id": "8272ec82-344c-4769-91ac-ccebce125777",
      "name": "SendProcessing",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -1104,
        752
      ],
      "parameters": {
        "text": "=...",
        "chatId": "={{ $('Trigger').item.json.message.chat.id }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "90dc3683-4e85-4c79-a44d-52f04e2d6e39",
      "name": "GetExecutionState",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        -816,
        1792
      ],
      "parameters": {
        "url": "=https://api.ainoflow.io/api/v1/storage/json/expense-app-processing/{{ $('Trigger').item.json.update_id }}",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "alwaysOutputData": true
    },
    {
      "id": "bf8eec4b-64b7-4580-840b-f2d910e949b7",
      "name": "Sonnet45",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        -176,
        1744
      ],
      "parameters": {
        "model": "anthropic/claude-sonnet-4.5",
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "9cd45908-6cb1-499a-9e8c-95f4cc69e4e5",
      "name": "GetAppSettings",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        -1552,
        1024
      ],
      "parameters": {
        "url": "https://api.ainoflow.io/api/v1/storage/json/config/expense-app-settings",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "alwaysOutputData": true
    },
    {
      "id": "a5ed9d9e-8fb1-4fba-8537-d4fe91932517",
      "name": "SaveAppSettings",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1488,
        1488
      ],
      "parameters": {
        "url": "https://api.ainoflow.io/api/v1/storage/json/config/expense-app-settings",
        "method": "PUT",
        "options": {},
        "sendBody": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "chat_id",
              "value": "={{ $('Trigger').item.json.message.chat.id }}"
            },
            {
              "name": "start_date",
              "value": "={{ $('Trigger').item.json.message.date }}"
            },
            {
              "name": "first_name",
              "value": "={{ $('Trigger').item.json.message.chat.first_name }}"
            }
          ]
        },
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "e6b007bf-589a-46b4-ae5e-0f0ae88bcd17",
      "name": "SaveExecutionState",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -912,
        752
      ],
      "parameters": {
        "url": "=https://api.ainoflow.io/api/v1/storage/json/expense-app-processing/{{ $('Trigger').item.json.update_id }}",
        "method": "PUT",
        "options": {},
        "sendBody": true,
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "chat_id",
              "value": "={{ $json.result.chat.id }}"
            },
            {
              "name": "message_id",
              "value": "={{ $json.result.message_id }}"
            }
          ]
        },
        "genericAuthType": "httpBearerAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "expiresMs",
              "value": "3600000"
            }
          ]
        }
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "50b5551e-ef7d-4590-81d0-37339c1a8794",
  "connections": {
    "Gpt4o": {
      "ai_languageModel": [
        [
          {
            "node": "AIAgent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Input": {
      "main": [
        [
          {
            "node": "GetAppSettings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Think": {
      "ai_tool": [
        [
          {
            "node": "ExpenseAssistant",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Switch": {
      "main": [
        [
          {
            "node": "WelcomeMessage",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "TextOutput",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "GetAudioFile",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "GetAttachedFile",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "GetAttachedPhoto",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Think1": {
      "ai_tool": [
        [
          {
            "node": "AIAgent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "AIAgent": {
      "main": [
        [
          {
            "node": "ReplyText",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Cleanup": {
      "main": [
        [
          {
            "node": "ForEachCategory",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Trigger": {
      "main": [
        [
          {
            "node": "Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sonnet45": {
      "ai_languageModel": [
        [
          {
            "node": "ExpenseAssistant",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "AgentInput": {
      "main": [
        [
          {
            "node": "AIAgent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculator": {
      "ai_tool": [
        [
          {
            "node": "ExpenseAssistant",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "FileOutput": {
      "main": [
        [
          {
            "node": "AgentInput",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IfFirstRun": {
      "main": [
        [
          {
            "node": "SaveAppSettings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "TextOutput": {
      "main": [
        [
          {
            "node": "AgentInput",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AudioOutput": {
      "main": [
        [
          {
            "node": "AgentInput",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ImageOutput": {
      "main": [
        [
          {
            "node": "AgentInput",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GetAudioFile": {
      "main": [
        [
          {
            "node": "TranscribeAudio",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IfStateExist": {
      "main": [
        [
          {
            "node": "DeleteProcessing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SimpleMemory": {
      "ai_memory": [
        [
          {
            "node": "AIAgent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "AssitantMemory": {
      "ai_memory": [
        [
          {
            "node": "ExpenseAssistant",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "GetAppSettings": {
      "main": [
        [
          {
            "node": "IfFirstRun",
            "type": "main",
            "index": 0
          },
          {
            "node": "IfAccessAllowed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "JsonStorageMcp": {
      "ai_tool": [
        [
          {
            "node": "ExpenseAssistant",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "SendProcessing": {
      "main": [
        [
          {
            "node": "SaveExecutionState",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ExtractFileText": {
      "main": [
        [
          {
            "node": "FileOutput",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ForEachCategory": {
      "main": [
        [
          {
            "node": "ForEachCategoryItem",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GetAttachedFile": {
      "main": [
        [
          {
            "node": "ExtractFileText",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IfAccessAllowed": {
      "main": [
        [
          {
            "node": "Switch",
            "type": "main",
            "index": 0
          },
          {
            "node": "SendProcessing",
            "type": "main",
            "index": 0
          },
          {
            "node": "GetExecutionState",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "NotAuthorizedMessage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "TranscribeAudio": {
      "main": [
        [
          {
            "node": "AudioOutput",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ExpenseAssistant": {
      "ai_tool": [
        [
          {
            "node": "AIAgent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "ExtractImageText": {
      "main": [
        [
          {
            "node": "ImageOutput",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GetAttachedPhoto": {
      "main": [
        [
          {
            "node": "ExtractImageText",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GetExecutionState": {
      "main": [
        [
          {
            "node": "IfStateExist",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "ForEachCategoryItem": {
      "main": [
        [
          {
            "node": "DeleteItem",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}