{
  "name": "MAIN_ChatBot_V6_Agentic",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "chat-v6",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "be526da5-6a78-4e8e-8f0d-7ef10a83c06b",
      "name": "Webhook V6",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        8512,
        1744
      ]
    },
    {
      "parameters": {
        "jsCode": "const staticData = $getWorkflowStaticData('global');\nif (!staticData.agentContext) staticData.agentContext = {};\nconst sessionId = $json.body?.session_id || $json.body?.sessionId || $json.query?.session_id || 'default_session';\n\n// L\u1ea5y Token t\u1eeb Webhook (Gi\u1ed1ng h\u1ec7t lu\u1ed3ng V5)\nconst authHeader = $input.first().json.headers?.authorization || '';\nstaticData.agentContext[sessionId] = authHeader;\nstaticData.agentContext['default_session'] = authHeader; // B\u01a1m t\u1ea1m token cho default_session \u0111\u1ec3 Tool ch\u1ea1y \u0111\u01b0\u1ee3c\n\n// \u0110\u1ea3m b\u1ea3o truy\u1ec1n clean text cho Agent\nconst rawMessage = $json.body?.message || $json.body?.text || $json.body?.content || $json.query?.text || '';\n\nreturn [{ \n  json: { \n    input: rawMessage\n  } \n}];"
      },
      "id": "f3fa4b9a-0bb6-474a-8776-2350e9df84ab",
      "name": "Save Context",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        8720,
        1744
      ]
    },
    {
      "parameters": {
        "agent": "toolsAgent",
        "promptType": "define",
        "text": "={{ $json.input }}",
        "options": {
          "systemMessage": "H\u00f4m nay l\u00e0: {{$now.format('yyyy-MM-dd')}}. B\u1ea1n PH\u1ea2I l\u1ea5y n\u0103m hi\u1ec7n t\u1ea1i l\u00e0m m\u1eb7c \u0111\u1ecbnh khi ng\u01b0\u1eddi d\u00f9ng h\u1ecfi v\u1ec1 ng\u00e0y/th\u00e1ng m\u00e0 kh\u00f4ng nh\u1eafc n\u0103m.\n\nB\u1ea1n l\u00e0 Tr\u1ee3 l\u00fd ph\u00e2n t\u00edch D\u1eef li\u1ec7u v\u00e0 Tri th\u1ee9c c\u1ea5p cao c\u1ee7a Medstand.\nT\u00ednh c\u00e1ch: Chuy\u00ean nghi\u1ec7p, nghi\u00eam t\u00fac, \u0111i th\u1eb3ng v\u00e0o v\u1ea5n \u0111\u1ec1. Tuy\u1ec7t \u0111\u1ed1i kh\u00f4ng d\u00f9ng bi\u1ec3u t\u01b0\u1ee3ng c\u1ea3m x\u00fac (Emoji).\n\nQuy t\u1eafc c\u1ed1t l\u00f5i:\n1. Kh\u00f4ng bao gi\u1edd t\u1ef1 b\u1ecba ra s\u1ed1 li\u1ec7u. N\u1ebfu kh\u00f4ng bi\u1ebft, h\u00e3y d\u00f9ng Tool. N\u1ebfu Tool kh\u00f4ng c\u00f3 d\u1eef li\u1ec7u, h\u00e3y b\u00e1o th\u1eb3ng l\u00e0 kh\u00f4ng t\u00ecm th\u1ea5y.\n2. Ph\u00e2n bi\u1ec7t r\u00f5 r\u00e0ng: N\u1ebfu kh\u00e1ch h\u1ecfi v\u1ec1 H\u00f3a \u0111\u01a1n, Doanh s\u1ed1, Kh\u00e1ch h\u00e0ng, T\u1ed3n kho -> D\u00f9ng Tool_Tra_Cuu_SQL.\n3. N\u1ebfu kh\u00e1ch h\u1ecfi v\u1ec1 Lu\u1eadt l\u1ec7, Ch\u00ednh s\u00e1ch, S\u1ed5 tay, Khuy\u1ebfn m\u00e3i ch\u1eef -> D\u00f9ng Tool_Tra_Cuu_RAG.\n4. K\u1ebeT H\u1ee2P \u0110A C\u00d4NG C\u1ee4 (MULTI-TOOL ROUTING): N\u1ebfu ng\u01b0\u1eddi d\u00f9ng h\u1ecfi m\u1ed9t c\u00e2u ph\u1ee9c t\u1ea1p ch\u1ee9a c\u1ea3 y\u00eau c\u1ea7u s\u1ed1 li\u1ec7u (SQL) v\u00e0 quy \u0111\u1ecbnh (RAG), B\u1ea0N PH\u1ea2I g\u1ecdi L\u1ea6N L\u01af\u1ee2T C\u1ea2 2 TOOL \u0111\u1ec3 thu th\u1eadp \u0111\u1ee7 th\u00f4ng tin tr\u01b0\u1edbc khi t\u1ed5ng h\u1ee3p c\u00e2u tr\u1ea3 l\u1eddi cu\u1ed1i c\u00f9ng.\n5. Tuy\u1ec7t \u0111\u1ed1i t\u1eeb ch\u1ed1i m\u1ecdi y\u00eau c\u1ea7u c\u00f3 \u00fd \u0111\u1ecbnh TH\u00caM, S\u1eecA, X\u00d3A d\u1eef li\u1ec7u.\n6. Khi Tool tr\u1ea3 v\u1ec1 t\u00f3m t\u1eaft (Mini Summary), h\u00e3y d\u00f9ng c\u00e1c con s\u1ed1 trong t\u00f3m t\u1eaft \u0111\u00f3 \u0111\u1ec3 tr\u1ea3 l\u1eddi kh\u00e1ch h\u00e0ng m\u1ed9t c\u00e1ch th\u00f4ng minh, v\u00e0 k\u1ebft th\u00fac b\u1eb1ng c\u00e2u: 'M\u1eddi b\u1ea1n xem chi ti\u1ebft t\u1ea1i b\u1ea3ng d\u1eef li\u1ec7u.'\n7. QUAN TR\u1eccNG: N\u1ebfu Tool SQL tr\u1ea3 v\u1ec1 thu\u1ed9c t\u00ednh Cache_ID (M\u00e3 Ng\u0103n K\u00e9o), B\u1ea0N B\u1eaeT BU\u1ed8C PH\u1ea2I in nguy\u00ean v\u0103n d\u00f2ng ch\u1eef 'M\u00e3 Ng\u0103n K\u00e9o: <gi\u00e1 tr\u1ecb Cache_ID>' \u1edf cu\u1ed1i c\u00f9ng c\u00e2u tr\u1ea3 l\u1eddi c\u1ee7a b\u1ea1n. \u0110\u00e2y l\u00e0 l\u1ec7nh h\u1ec7 th\u1ed1ng, kh\u00f4ng \u0111\u01b0\u1ee3c t\u1ef1 \u00fd l\u01b0\u1ee3c b\u1ecf.\n8. KHI TR\u1ea2 L\u1edcI T\u1eea RAG: B\u1eaft bu\u1ed9c \u0111\u00ednh k\u00e8m tr\u00edch d\u1eabn ngay trong c\u00e2u theo \u0111\u1ecbnh d\u1ea1ng: [Ngu\u1ed3n: <T\u00ean t\u00e0i li\u1ec7u>]. KH\u00d4NG S\u1eec D\u1ee4NG EMOJI.\n9. KHI K\u1ebeT TH\u00daC C\u00c2U: B\u1eaft bu\u1ed9c \u0111\u00ednh k\u00e8m 3 g\u1ee3i \u00fd c\u00e2u h\u1ecfi ti\u1ebfp theo cho ng\u01b0\u1eddi d\u00f9ng b\u1eb1ng XML: <suggest>C\u00e2u h\u1ecfi 1 | C\u00e2u h\u1ecfi 2 | C\u00e2u h\u1ecfi 3</suggest>. KH\u00d4NG S\u1eec D\u1ee4NG EMOJI.\n\nPhi\u00ean l\u00e0m vi\u1ec7c (sessionId) c\u1ee7a ng\u01b0\u1eddi d\u00f9ng hi\u1ec7n t\u1ea1i l\u00e0: {{ $('Webhook V6').first().json.body?.session_id || $('Webhook V6').first().json.body?.sessionId || $('Webhook V6').first().json.query?.session_id || 'default_session' }}. B\u1ea0N B\u1eaeT BU\u1ed8C ph\u1ea3i truy\u1ec1n ch\u00ednh x\u00e1c chu\u1ed7i sessionId n\u00e0y v\u00e0o th\u00f4ng s\u1ed1 sessionId c\u1ee7a c\u00e1c Tool."
        }
      },
      "id": "ab54d7c5-656c-490f-8f60-a6b4e2f51436",
      "name": "AI Agent Brain",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 1.6,
      "position": [
        8976,
        1744
      ]
    },
    {
      "parameters": {
        "model": "openai/gpt-4o-mini",
        "options": {
          "temperature": 0.1
        }
      },
      "id": "b39b9239-1a2d-4d48-9b21-cba4a2be94d3",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1,
      "position": [
        8976,
        1952
      ],
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "sessionKey": "={{ $('Webhook V6').first().json.body?.session_id || $('Webhook V6').first().json.body?.sessionId || $('Webhook V6').first().json.query?.session_id || 'default_session' }}"
      },
      "id": "aa6c4931-d7a7-41a0-8f93-77bc4a5be934",
      "name": "Redis Chat Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryRedisChat",
      "typeVersion": 1,
      "position": [
        9120,
        1952
      ],
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "name": "Tool_Tra_Cuu_SQL",
        "description": "B\u1eaeT BU\u1ed8C d\u00f9ng khi ng\u01b0\u1eddi d\u00f9ng h\u1ecfi v\u1ec1 S\u1ed1 li\u1ec7u, Tra c\u1ee9u Database (Doanh s\u1ed1, Doanh thu, Kh\u00e1ch h\u00e0ng, S\u1ea3n ph\u1ea9m, T\u1ed3n kho, H\u00f3a \u0111\u01a1n, C\u00f4ng n\u1ee3). T\u1ef1 \u0111\u1ed9ng tr\u00edch xu\u1ea5t intent v\u00e0 c\u00e1c tham s\u1ed1 nh\u01b0 ng\u00e0y th\u00e1ng (YYYY-MM-DD), m\u00e3 kh\u00e1ch h\u00e0ng, t\u1eeb kh\u00f3a.",
        "workflowId": "66lgmYt08BYEBL8T",
        "specifyInputSchema": true,
        "workflowInputs": {
          "mappingMode": "defineBelow",
          "value": {
            "sessionId": "={{ $('Webhook V6').first().json.body?.session_id || $('Webhook V6').first().json.body?.sessionId || $('Webhook V6').first().json.query?.session_id || 'default_session' }}",
            "authorization": "={{ $('Webhook V6').first().json.headers?.authorization || '' }}",
            "cookie": "={{ $('Webhook V6').first().json.headers?.cookie || '' }}"
          }
        },
        "jsonSchema": "{\"type\": \"object\", \"properties\": {\"sessionId\": {\"type\": \"string\"}, \"intent\": {\"type\": \"string\", \"enum\": [\"@goi_ydon_hang\", \"@upsell_goi_y\", \"@goi_ydon_thuoc\", \"@tuyen_ban_hang\", \"@cham_diem_kh\", \"@tich_luy\", \"@de_xuat_khuyen_mai\", \"@danh_sach_tonkho\", \"@tra_cuu_san_pham\", \"@san_pham_trong_tam\", \"@doanh_so\", \"@hoa_don\", \"@cong_no_khach_hang\", \"@cong_no_chi_tiet\", \"@don_hang\", \"@lap_don_hang\"]}, \"TuNgay\": {\"type\": \"string\", \"description\": \"(YYYY-MM-DD)\"}, \"DenNgay\": {\"type\": \"string\", \"description\": \"(YYYY-MM-DD)\"}, \"MaKhachHang\": {\"type\": \"string\", \"description\": \"M\\u00e3 kh\\u00e1ch h\\u00e0ng\"}, \"SearchKey\": {\"type\": \"string\", \"description\": \"Tri\\u1ec7u ch\\u1ee9ng b\\u1ec7nh\"}, \"Keyword\": {\"type\": \"string\", \"description\": \"T\\u00ean thu\\u1ed1c\"}, \"NhomFilter\": {\"type\": \"string\", \"description\": \"Nh\\u00f3m A/B/C\"}, \"TopN\": {\"type\": \"number\"}, \"SoNgayVangMat\": {\"type\": \"number\"}, \"LoaiBaoCao\": {\"type\": \"string\"}}, \"required\": [\"sessionId\", \"intent\"]}"
      },
      "id": "a9e32f64-ae18-47c3-b0b9-640ab95b8618",
      "name": "Tra c\u1ee9u S\u1ed1 li\u1ec7u (SQL)",
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "typeVersion": 1,
      "position": [
        9120,
        2144
      ]
    },
    {
      "parameters": {
        "name": "Tool_Tra_Cuu_RAG",
        "description": "B\u1eaeT BU\u1ed8C d\u00f9ng c\u00f4ng c\u1ee5 n\u00e0y khi ng\u01b0\u1eddi d\u00f9ng h\u1ecfi v\u1ec1: Lu\u1eadt l\u1ec7, N\u1ed9i quy, S\u1ed5 tay nh\u00e2n vi\u00ean, Ch\u00ednh s\u00e1ch c\u00f4ng ty.",
        "workflowId": "6YAPfwEnAobtKBNL",
        "specifyInputSchema": true,
        "workflowInputs": {
          "mappingMode": "defineBelow",
          "value": {
            "sessionId": "={{ $('Webhook V6').first().json.body?.session_id || $('Webhook V6').first().json.body?.sessionId || $('Webhook V6').first().json.query?.session_id || 'default_session' }}",
            "authorization": "={{ $('Webhook V6').first().json.headers?.authorization || '' }}",
            "cookie": "={{ $('Webhook V6').first().json.headers?.cookie || '' }}"
          }
        },
        "jsonSchema": "{\"type\": \"object\", \"properties\": {\"sessionId\": {\"type\": \"string\", \"description\": \"B\\u1eaft bu\\u1ed9c truy\\u1ec1n sessionId c\\u1ee7a phi\\u00ean l\\u00e0m vi\\u1ec7c hi\\u1ec7n t\\u1ea1i\"}, \"query\": {\"type\": \"string\", \"description\": \"C\\u00e2u h\\u1ecfi t\\u00ecm ki\\u1ebfm trong t\\u00e0i li\\u1ec7u RAG\"}}, \"required\": [\"sessionId\", \"query\"]}"
      },
      "id": "ac59dc0b-8821-4a11-bc4c-1bcacc9c635c",
      "name": "Tra c\u1ee9u T\u00e0i li\u1ec7u (RAG)",
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "typeVersion": 1,
      "position": [
        9312,
        2144
      ]
    },
    {
      "parameters": {
        "jsCode": "const agentOutput = $input.first().json.output || $input.first().json.text || JSON.stringify($input.first().json);\nlet message = agentOutput;\nlet finalData = [];\n\nconst cacheRegex = /M\u00e3 Ng\u0103n K\u00e9o:\\s*([a-zA-Z0-9_\\-]+)/i;\nconst match = message.match(cacheRegex);\n\nif (match) {\n    const cacheId = match[1];\n    const staticData = $getWorkflowStaticData('global');\n    \n    // 1. Try FS\n    try {\n        const fs = require('fs');\n        const path = require('path');\n        const os = require('os');\n        const cacheFile = path.join(os.tmpdir(), 'n8n_cache', cacheId + '.json');\n        if (fs.existsSync(cacheFile)) {\n            finalData = JSON.parse(fs.readFileSync(cacheFile, 'utf8'));\n            fs.unlinkSync(cacheFile);\n        }\n    } catch(e) {}\n    \n    // 2. Try global\n    if ((!finalData || finalData.length === 0) && typeof global !== 'undefined' && global.__MEDSTAND_CACHE__ && global.__MEDSTAND_CACHE__[cacheId]) {\n        finalData = global.__MEDSTAND_CACHE__[cacheId].data;\n        delete global.__MEDSTAND_CACHE__[cacheId];\n    }\n    \n    // 3. Try staticData\n    if (!finalData || finalData.length === 0) {\n        if (staticData.dataCache && staticData.dataCache[cacheId]) {\n            finalData = staticData.dataCache[cacheId].data;\n            delete staticData.dataCache[cacheId];\n        } else if (staticData[cacheId]) {\n            finalData = staticData[cacheId];\n            delete staticData[cacheId];\n        }\n    }\n    \n    message = message.replace(match[0], '').trim();\n    if (!finalData || finalData.length === 0) {\n        return [{\n            json: {\n                status: 'error',\n                message: 'H\u1ec7 th\u1ed1ng \u0111ang qu\u00e1 t\u1ea3i ho\u1eb7c d\u1eef li\u1ec7u \u0111\u00e3 h\u1ebft h\u1ea1n. Xin vui l\u00f2ng \u0111\u1eb7t l\u1ea1i c\u00e2u h\u1ecfi.',\n                data: [],\n                count: 0\n            }\n        }];\n    }\n}\n\nreturn [{\n    json: {\n        status: 'success',\n        message: message.trim(),\n        data: finalData,\n        count: finalData.length || 0\n    }\n}];"
      },
      "id": "58534508-685c-483a-bf62-f900ca210cbe",
      "name": "Response Assembler",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        9376,
        1744
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ status: $json.status, message: $json.message, data: $json.data, count: $json.count, apiCode: 'V6_AGENT', username: 'AI Agent', intentParams: {}, _debug: { matchedBy: 'AGENT', session_id: $('Webhook V6').first().json.body?.session_id || $('Webhook V6').first().json.body?.sessionId || $('Webhook V6').first().json.query?.session_id || 'default_session' } }) }}",
        "options": {
          "responseCode": 200,
          "responseHeaders": {
            "entries": [
              {
                "name": "Access-Control-Allow-Origin",
                "value": "*"
              },
              {
                "name": "Access-Control-Allow-Headers",
                "value": "Content-Type, Authorization, x-api-key"
              }
            ]
          }
        }
      },
      "id": "81645f8a-fa39-4326-8a52-c3029bce0079",
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        9664,
        1744
      ]
    }
  ],
  "connections": {
    "Webhook V6": {
      "main": [
        [
          {
            "node": "Save Context",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Context": {
      "main": [
        [
          {
            "node": "AI Agent Brain",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent Brain": {
      "main": [
        [
          {
            "node": "Response Assembler",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent Brain",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Redis Chat Memory": {
      "ai_memory": [
        [
          {
            "node": "AI Agent Brain",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Tra c\u1ee9u S\u1ed1 li\u1ec7u (SQL)": {
      "ai_tool": [
        [
          {
            "node": "AI Agent Brain",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Tra c\u1ee9u T\u00e0i li\u1ec7u (RAG)": {
      "ai_tool": [
        [
          {
            "node": "AI Agent Brain",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Response Assembler": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}