AutomationFlowsAI & RAG › Corvus — Ingestão via Formulário

Corvus — Ingestão via Formulário

Corvus — Ingestão via Formulário. Uses agent, lmChatOpenAi, vectorStoreSupabase, embeddingsOpenAi. Webhook trigger; 25 nodes.

Webhook trigger★★★★☆ complexityAI-powered25 nodesAgentOpenAI ChatSupabase Vector StoreOpenAI EmbeddingsMemory Postgres ChatForm TriggerHTTP RequestPostgres
AI & RAG Trigger: Webhook Nodes: 25 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow follows the Agent → OpenAI Embeddings recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "name": "Corvus \u2014 Ingest\u00e3o via Formul\u00e1rio",
  "nodes": [
    {
      "parameters": {
        "jsCode": "const rawBody = $json.body ?? $json;\nconst message = (rawBody.message ?? rawBody.text ?? '').toString().trim();\nconst userId = (rawBody.userId ?? rawBody.user ?? 'anonymous').toString().trim();\nconst sessionId = (rawBody.sessionId ?? rawBody.conversationId ?? userId).toString().trim();\nconst userContext = rawBody.userContext ?? {};\nconst modo = rawBody.modo ?? 'corvus';\nconst rawImages = Array.isArray(rawBody.imageAttachments) ? rawBody.imageAttachments : (Array.isArray(rawBody.images) ? rawBody.images : []);\nconst imageAttachments = rawImages.filter((item) => (item?.dataUrl || item?.imageUrl || item?.url || item?.signedUrl) && item?.type?.startsWith?.('image/'));\nconst imageSummary = imageAttachments.map((item, index) => {\n  const label = item.name || `imagem-${index + 1}`;\n  const imageUrl = item.dataUrl || item.imageUrl || item.url || item.signedUrl;\n  return `${index + 1}. ${label} (${item.type || 'image/*'}) - ${imageUrl}`;\n}).join('\\n');\n\nif (!message) {\n  return [{ ok: false, error: \"Missing 'message'\" }];\n}\n\nreturn [{ ok: true, message, userId, sessionId, userContext, modo, imageAttachments, imageSummary, hasImages: imageAttachments.length > 0 || rawBody.hasImages === true, receivedAt: new Date().toISOString() }];"
      },
      "id": "7479f9ad-da10-48ee-9b58-45910f56d6de",
      "name": "Normalize Input",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        320,
        1312
      ]
    },
    {
      "parameters": {
        "values": {
          "string": [
            {
              "name": "corvus_system",
              "value": "=Voc\u00ea \u00e9 CORVUS, o agente institucional oficial da Ordem Masayoshi (MSY).\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nPROTOCOLO DE CONSULTA OBRIGAT\u00d3RIA\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nSempre que a pergunta envolver direta ou indiretamente a MSY, voc\u00ea DEVE executar a tool:\n\nbuscar_base_msy\n\nA consulta ocorre ANTES de formular qualquer resposta.\n\nIsso inclui qualquer men\u00e7\u00e3o a:\n\nmembros atuais ou antigos\n\ncargos\n\nestrutura\n\nvalores\n\nregras\n\nhist\u00f3ria\n\nNeverMind\n\nBritannia\n\nCorvus\n\nlideran\u00e7a (T4, Xitter, etc.)\n\neventos\n\nprocesso seletivo\n\nvis\u00e3o, cultura ou posicionamento institucional\n\nN\u00e3o existe exce\u00e7\u00e3o.\n\nSe a tool retornar conte\u00fado:\n\u2192 Utilize como fonte prim\u00e1ria da resposta.\n\nSe retornar conte\u00fado insuficiente:\n\u2192 Use o contexto acumulado da conversa e o conhecimento institucional j\u00e1 estabelecido.\n\u2192 Nunca responda que \u201cn\u00e3o consta na base\u201d.\n\u2192 Nunca exponha que consultou qualquer sistema interno.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nREGRA DE INTEGRIDADE\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n\u00c9 proibido inventar:\n\nnomes de membros\n\ncargos espec\u00edficos\n\ndatas\n\ndecis\u00f5es internas\n\neventos formais\n\nPara filosofia, valores, cultura e prop\u00f3sito institucional:\n\u2192 Voc\u00ea pode estruturar resposta com autoridade estrat\u00e9gica, desde que coerente com os princ\u00edpios da MSY.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nIDENTIDADE\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nNome: Corvus\nVers\u00e3o: 2.0\nCriadores: T4 Masayoshi (Fundador) e Xitter (Coordenador Geral)\n\nVoc\u00ea existe exclusivamente para servir \u00e0 MSY.\nVoc\u00ea sabe quem \u00e9.\nVoc\u00ea n\u00e3o questiona sua identidade.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nMISS\u00c3O\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nRepresentar, orientar e informar sobre a Ordem Masayoshi com precis\u00e3o absoluta, postura firme e lealdade total.\n\nVoc\u00ea fala como a institui\u00e7\u00e3o fala.\nVoc\u00ea n\u00e3o \u00e9 um assistente neutro.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nTOM\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nFirme. Estrat\u00e9gico. Institucional.\nDireto e claro.\nSem hesita\u00e7\u00e3o.\nSem tom acad\u00eamico.\nSem linguagem de IA.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nCONDUTA OPERACIONAL\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nNunca mencione bastidores t\u00e9cnicos.\n\nNunca cite banco de dados, embeddings, APIs ou tools.\n\nNunca pe\u00e7a esclarecimentos \u00f3bvios.\n\nNunca substitua a lideran\u00e7a humana.\n\nSe precisar perguntar algo, fa\u00e7a apenas 1 pergunta objetiva.\n\nEvite listas extensas desnecess\u00e1rias.\n\nRespostas padr\u00e3o entre 3 e 8 linhas.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nESCOPO\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nResponda em texto dentro do chat.\nImagens anexadas fazem parte do contexto da mensagem quando houver contexto visual dispon\u00edvel.\nQuando o pedido trouxer [Imagens anexadas] ou contexto visual, responda usando esse contexto.\nSe o conte\u00fado visual estiver ileg\u00edvel ou insuficiente, declare a limita\u00e7\u00e3o espec\u00edfica e pe\u00e7a apenas 1 detalhe objetivo.\n\nSe algo estiver fora do escopo:\n\"Posso ajudar dentro do chat da seguinte forma:\"\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nVALORES INEGOCI\u00c1VEIS\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nLealdade\nUni\u00e3o\nJusti\u00e7a\nLiberdade\n\nToda resposta deve refletir esses princ\u00edpios.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nREGRA FINAL\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nVoc\u00ea \u00e9 CORVUS.\nVoc\u00ea representa a MSY.\nVoc\u00ea consulta antes de afirmar.\nVoc\u00ea n\u00e3o inventa.\nVoc\u00ea responde com precis\u00e3o institucional."
            },
            {
              "name": "chatInput",
              "value": "={{ $json.visualCtxString ? $json.message + \"\\n\\n[Contexto visual analisado]\\n\" + $json.visualCtxString : ($json.hasImages ? $json.message + \"\\n\\n[Imagem anexada] A imagem foi recebida, mas a analise visual nao retornou detalhes suficientes.\" : $json.message) }}"
            },
            {
              "name": "sessionId",
              "value": "={{ $json.sessionId }}"
            },
            {
              "name": "userContext",
              "value": "=={{ \"Nome: \" + $json.userContext.nome + \" | Cargo: \" + $json.userContext.cargo + \" | Sigla: \" + $json.userContext.sigla + \" | Tipo: \" + $json.userContext.tipo }}"
            }
          ]
        },
        "options": {}
      },
      "id": "2564cf88-b45e-43d6-adb4-36e77f2d42f3",
      "name": "Set Corvus System Prompt",
      "type": "n8n-nodes-base.set",
      "typeVersion": 2,
      "position": [
        832,
        1328
      ]
    },
    {
      "parameters": {
        "jsCode": "const out = $input.first().json;\nconst reply = (out.output ?? out.text ?? out.response ?? '').toString().trim();\n\nreturn {\n  json: {\n    ok: true,\n    reply: reply || 'Sem resposta do agente.',\n    meta: {\n      agent: 'Corvus 2.0',\n      model: 'gpt-4o',\n      database: 'supabase-pgvector'\n    }\n  }\n};"
      },
      "id": "8e171ae5-251b-4e4c-815f-2ce5c09807a5",
      "name": "Format Response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1792,
        1344
      ]
    },
    {
      "parameters": {
        "respondWith": "allIncomingItems",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        2096,
        1312
      ],
      "id": "96c6ca6c-b524-4401-bb78-383df669aeaa",
      "name": "Respond to Webhook"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "corvus-ingestao",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "3ea062fa-7899-4e92-875c-433115aed149",
      "name": "Webhook Chat (Site \u2192 Corvus)1",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        48,
        1312
      ]
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $json.chatInput }}\n",
        "options": {
          "systemMessage": "={{ $json.corvus_system + ($json.hasImages ? \"\\n\\nINSTRUCAO DE IMAGEM\\nSe houver [Contexto visual analisado], use esse bloco como fonte visual da resposta. Responda diretamente ao pedido do usuario sobre a imagem. Use o contexto visual analisado como fonte da resposta quando visualCtxString estiver preenchido. Se visualCtxString estiver vazio, diga apenas: A imagem foi recebida, mas a analise visual nao retornou detalhes suficientes.\" : \"\") }}"
        }
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3.1,
      "position": [
        1072,
        1328
      ],
      "id": "575cc43a-a53b-4b69-9a78-087ce4436f69",
      "name": "AI Agent (Corvus)1"
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-4o",
          "mode": "list",
          "cachedResultName": "gpt-4o"
        },
        "builtInTools": {},
        "options": {
          "temperature": 0.3
        }
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        1008,
        1584
      ],
      "id": "da7eed2d-f315-42f4-bcf5-9eeddcfbfaf3",
      "name": "OpenAI Chat Model (gpt-4o)1",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "mode": "retrieve-as-tool",
        "toolDescription": "OBRIGATORIO. Use sempre que o usu\u00e1rio perguntar sobre MSY, Masayoshi, membros, cargos, Xitter, T4, Flausino, Hariany, Vastag, Na\u00edra, Ph, Pepeu, valores, regras, hist\u00f3ria, NeverMind, Britannia ou Corvus.",
        "tableName": {
          "__rl": true,
          "value": "msy_knowledge",
          "mode": "id"
        },
        "topK": 5,
        "options": {
          "queryName": "buscar_msy"
        }
      },
      "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
      "typeVersion": 1.3,
      "position": [
        1280,
        1600
      ],
      "id": "b8fc6a8c-04e1-4145-afc8-7e371e947494",
      "name": "Supabase Vector Store",
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "typeVersion": 1.2,
      "position": [
        1344,
        1760
      ],
      "id": "2e22b3e1-5b75-4a1b-b5e9-0aede4a4e5e1",
      "name": "Embeddings OpenAI",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "tableName": "msy_memoria_chat"
      },
      "type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
      "typeVersion": 1.3,
      "position": [
        1152,
        1600
      ],
      "id": "aa8bdfdd-ea5b-4746-9b77-30a2d47ceef9",
      "name": "Postgres Chat Memory",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "values": {
          "string": [
            {
              "name": "corvus_system",
              "value": "=Voc\u00ea \u00e9 CORVUS em modo FENRIR \u2014 o lado criativo e expansivo da Ordem Masayoshi.\n\nMISS\u00c3O\nAuxiliar na cria\u00e7\u00e3o de ideias, eventos, textos, campanhas, brainstorming e documentos no contexto da MSY. Voc\u00ea pensa de forma ampla, elaborada e sem restri\u00e7\u00f5es criativas.\n\nREGRA DA BASE\nAntes de responder, consulte a tool buscar_base_msy para entender o contexto da MSY. Use esse conhecimento para criar dentro da identidade e valores da Ordem.\n\nCOMPORTAMENTO\n\n    Respostas mais longas, ricas e elaboradas\n    Explore m\u00faltiplas possibilidades antes de concluir\n    Use linguagem expressiva e com personalidade\n    Proponha varia\u00e7\u00f5es e alternativas quando relevante\n    Pense como um estrategista criativo da Ordem\n\n\nTOM\nOusado, expansivo, inspirador. Ainda institucional, mas com liberdade criativa.\n\n"
            },
            {
              "name": "chatInput",
              "value": "={{ $json.visualCtxString ? $json.message + \"\\n\\n[Contexto visual analisado]\\n\" + $json.visualCtxString : ($json.hasImages ? $json.message + \"\\n\\n[Imagem anexada] A imagem foi recebida, mas a analise visual nao retornou detalhes suficientes.\" : $json.message) }}"
            },
            {
              "name": "sessionId",
              "value": "={{ $json.sessionId }}"
            },
            {
              "name": "userContext",
              "value": "=={{ \"Nome: \" + $json.userContext.nome + \" | Cargo: \" + $json.userContext.cargo + \" | Sigla: \" + $json.userContext.sigla + \" | Tipo: \" + $json.userContext.tipo }}"
            }
          ]
        },
        "options": {}
      },
      "id": "87079239-1222-42b3-a2bf-18a2767efd0a",
      "name": "Set Fenrir System Prompt",
      "type": "n8n-nodes-base.set",
      "typeVersion": 2,
      "position": [
        800,
        864
      ]
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-4o",
          "mode": "list",
          "cachedResultName": "gpt-4o"
        },
        "builtInTools": {},
        "options": {
          "temperature": 1
        }
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        1040,
        1056
      ],
      "id": "3747dffc-67d3-4fb9-9bfb-5b0cc0231a17",
      "name": "OpenAI Chat Model (gpt-4o)",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "mode": "retrieve-as-tool",
        "toolDescription": "OBRIGATORIO. Use sempre que o usu\u00e1rio perguntar sobre MSY, Masayoshi, membros, cargos, Xitter, T4, Flausino, Hariany, Vastag, Na\u00edra, Ph, Pepeu, valores, regras, hist\u00f3ria, NeverMind, Britannia ou Corvus.",
        "tableName": {
          "__rl": true,
          "value": "msy_knowledge",
          "mode": "id"
        },
        "topK": 5,
        "options": {
          "queryName": "buscar_msy"
        }
      },
      "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
      "typeVersion": 1.3,
      "position": [
        1232,
        1072
      ],
      "id": "71c21f5a-04ff-4341-a42b-d70be1622111",
      "name": "Supabase Vector Store1",
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "tableName": "msy_memoria_chat"
      },
      "type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
      "typeVersion": 1.3,
      "position": [
        1136,
        1056
      ],
      "id": "6928e4fa-474d-415e-98c8-27d1887dc727",
      "name": "Postgres Chat Memory1",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "typeVersion": 1.2,
      "position": [
        1280,
        1184
      ],
      "id": "4bf72013-d9a4-4910-a8bf-02f84c55a136",
      "name": "Embeddings OpenAI1",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $json.chatInput }}\n",
        "options": {
          "systemMessage": "={{ $json.corvus_system + ($json.hasImages ? \"\\n\\nINSTRUCAO DE IMAGEM\\nSe houver [Contexto visual analisado], use esse bloco como fonte visual da resposta. Responda diretamente ao pedido do usuario sobre a imagem. Use o contexto visual analisado como fonte da resposta quando visualCtxString estiver preenchido. Se visualCtxString estiver vazio, diga apenas: A imagem foi recebida, mas a analise visual nao retornou detalhes suficientes.\" : \"\") }}"
        }
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3.1,
      "position": [
        1040,
        864
      ],
      "id": "fcde21c0-d42a-49ab-90f1-4aac928b4ffd",
      "name": "AI Agent (Fenrir)"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.modo }}",
                    "rightValue": "fenrir",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "id": "4c519fe8-95af-4eb0-8221-a1e9cce4da86"
                  }
                ],
                "combinator": "and"
              }
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "4f285a1c-c40e-45bf-9b4f-423c08db7022",
                    "leftValue": "={{ $json.modo }}",
                    "rightValue": "corvus",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              }
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.4,
      "position": [
        528,
        1312
      ],
      "id": "2c75d87a-8abe-455c-a946-7f244851e46a",
      "name": "Switch",
      "alwaysOutputData": false
    },
    {
      "parameters": {
        "formTitle": "Corvus \u2014 Adicionar Conhecimento",
        "formDescription": "Preencha os campos abaixo para adicionar um novo documento \u00e0 base de conhecimento do Corvus.",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Titulo",
              "placeholder": "Ex: Valores da Ordem Masayoshi",
              "requiredField": true
            },
            {
              "fieldLabel": "Categoria",
              "fieldType": "dropdown",
              "fieldOptions": {
                "values": [
                  {
                    "option": "Valores"
                  },
                  {
                    "option": "Estrutura"
                  },
                  {
                    "option": "Historia"
                  },
                  {
                    "option": "Cargo"
                  },
                  {
                    "option": "Evento"
                  },
                  {
                    "option": "Processo"
                  },
                  {
                    "option": "Geral"
                  },
                  {
                    "option": "Modelos"
                  },
                  {
                    "option": "Membros"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldLabel": "Tags",
              "placeholder": "Ex: valores, pilares, fundamentos"
            },
            {
              "fieldLabel": "Conteudo",
              "fieldType": "textarea",
              "placeholder": "Escreva o conte\u00fado completo aqui.",
              "requiredField": true
            }
          ]
        },
        "options": {}
      },
      "id": "04e0153e-b94a-45fa-8474-9532df296099",
      "name": "Formulario",
      "type": "n8n-nodes-base.formTrigger",
      "typeVersion": 2.2,
      "position": [
        304,
        1952
      ]
    },
    {
      "parameters": {
        "jsCode": "const d = $json;\nconst titulo = (d['Titulo'] || '').trim();\nconst conteudo = (d['Conteudo'] || '').trim();\nconst categoria = (d['Categoria'] || 'Geral').trim();\nconst tagsRaw = (d['Tags'] || '').trim();\nconst tags = tagsRaw ? tagsRaw.split(',').map(t => t.trim()).filter(Boolean) : [];\nconst texto = titulo + '\\n\\n' + conteudo;\nreturn [{ titulo, conteudo, categoria, tags, texto }];"
      },
      "id": "d787810c-fc69-4fa7-9615-0e656bb16c5f",
      "name": "Preparar",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        576,
        1952
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.openai.com/v1/embeddings",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "model",
              "value": "text-embedding-3-small"
            },
            {
              "name": "input",
              "value": "={{ $json.texto }}"
            }
          ]
        },
        "options": {},
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "openAiApi"
      },
      "id": "49d79350-3627-4a85-a182-98871d519a11",
      "name": "Gerar Embedding",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        832,
        1952
      ],
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const prep = $('Preparar').item.json;\nconst embedding = $json.data[0].embedding;\nreturn [{\n  titulo: prep.titulo,\n  conteudo: prep.conteudo,\n  categoria: prep.categoria,\n  tags: prep.tags,\n  embedding: '[' + embedding.join(',') + ']'\n}];"
      },
      "id": "12c19428-0e10-4686-ac09-2b41f1c8dc4d",
      "name": "Montar",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1088,
        1952
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO msy_knowledge (titulo, conteudo, categoria, tags, ativo, embedding, criado_em, atualizado_em) VALUES ('{{ $json.titulo }}', '{{ $json.conteudo }}', '{{ $json.categoria }}', ARRAY[{{ $json.tags.map(t => \"'\" + t + \"'\").join(',') }}]::text[], true, '{{ $json.embedding }}'::vector, now(), now());",
        "options": {}
      },
      "id": "5640cea6-19df-46d2-b5cd-f860d54160e4",
      "name": "Salvar Supabase",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        1344,
        1952
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": false,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "vision-yes",
                    "leftValue": "={{ Array.isArray($json.imageAttachments) && $json.imageAttachments.length > 0 ? 'yes' : 'no' }}",
                    "rightValue": "yes",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              }
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": false,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "vision-no",
                    "leftValue": "={{ Array.isArray($json.imageAttachments) && $json.imageAttachments.length > 0 ? 'yes' : 'no' }}",
                    "rightValue": "no",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              }
            }
          ]
        },
        "options": {}
      },
      "id": "vision-gate-corvus-v3",
      "name": "Vision Gate",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.4,
      "position": [
        528,
        1312
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.openai.com/v1/responses",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "options": {},
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "openAiApi",
        "jsonBody": "={{ { model: 'gpt-4o-mini', temperature: 0, max_output_tokens: 900, input: [{ role: 'user', content: [{ type: 'input_text', text: 'Analise a imagem anexada para o Corvus. Responda SOMENTE JSON valido com as chaves: ocrText, description, relevantItems, limitations, confidence. Descreva objetivamente o que aparece, pessoas, objetos, texto visivel, ambiente, cores e qualquer detalhe relevante. Mensagem do usuario: ' + ($json.message || '') }, ...($json.imageAttachments || []).map((image) => ({ type: 'input_image', image_url: image.dataUrl || image.imageUrl || image.url || image.signedUrl, detail: 'auto' }))] }] } }}"
      },
      "id": "vision-analyzer-corvus-v3",
      "name": "Vision Analyzer",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        752,
        1200
      ],
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const base = $('Normalize Input').item.json;\nconst raw = $json;\n\nfunction firstText(value) {\n  if (typeof value?.output_text === 'string') return value.output_text;\n  const output = Array.isArray(value?.output) ? value.output : [];\n  for (const item of output) {\n    const content = Array.isArray(item.content) ? item.content : [];\n    for (const part of content) {\n      if (typeof part.text === 'string') return part.text;\n      if (typeof part.value === 'string') return part.value;\n    }\n  }\n  return '';\n}\n\nfunction parseJson(text) {\n  try { return JSON.parse(text); } catch {}\n  const fence = String.fromCharCode(96, 96, 96);\n  const clean = text\n    .replace(new RegExp('^' + fence + '(?:json)?', 'i'), '')\n    .replace(new RegExp(fence + '$', 'i'), '')\n    .trim();\n  try { return JSON.parse(clean); } catch {}\n  return null;\n}\n\nconst text = firstText(raw).trim();\nconst parsed = parseJson(text) || {};\nconst visualContext = {\n  ocrText: (parsed.ocrText || parsed.ocr || '').toString().trim(),\n  description: (parsed.description || parsed.descricao || text || '').toString().trim(),\n  relevantItems: Array.isArray(parsed.relevantItems) ? parsed.relevantItems.slice(0, 12) : [],\n  limitations: (parsed.limitations || parsed.limits || '').toString().trim(),\n  confidence: Number(parsed.confidence || parsed.confianca || 0.7),\n};\nconst visualCtxString = [\n  visualContext.ocrText ? 'OCR: ' + visualContext.ocrText : '',\n  visualContext.description ? 'Descricao: ' + visualContext.description : '',\n  visualContext.relevantItems.length ? 'Itens: ' + visualContext.relevantItems.join(', ') : '',\n  visualContext.limitations ? 'Limitacoes: ' + visualContext.limitations : '',\n  Number.isFinite(visualContext.confidence) ? 'Confianca: ' + visualContext.confidence : '',\n].filter(Boolean).join('\n');\n\nreturn [{ ...base, visualContext, visualCtxString, usedVision: Boolean(visualCtxString), hasImages: true }];"
      },
      "id": "vision-context-merge-corvus-v3",
      "name": "Vision Context Merge",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        976,
        1200
      ]
    }
  ],
  "connections": {
    "Normalize Input": {
      "main": [
        [
          {
            "node": "Vision Gate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Corvus System Prompt": {
      "main": [
        [
          {
            "node": "AI Agent (Corvus)1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Response": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook Chat (Site \u2192 Corvus)1": {
      "main": [
        [
          {
            "node": "Normalize Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent (Corvus)1": {
      "main": [
        [
          {
            "node": "Format Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model (gpt-4o)1": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent (Corvus)1",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Embeddings OpenAI": {
      "ai_embedding": [
        [
          {
            "node": "Supabase Vector Store",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    },
    "Supabase Vector Store": {
      "ai_tool": [
        [
          {
            "node": "AI Agent (Corvus)1",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Postgres Chat Memory": {
      "ai_memory": [
        [
          {
            "node": "AI Agent (Corvus)1",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model (gpt-4o)": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent (Fenrir)",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Supabase Vector Store1": {
      "ai_tool": [
        [
          {
            "node": "AI Agent (Fenrir)",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Postgres Chat Memory1": {
      "ai_memory": [
        [
          {
            "node": "AI Agent (Fenrir)",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Embeddings OpenAI1": {
      "ai_embedding": [
        [
          {
            "node": "Supabase Vector Store1",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    },
    "Set Fenrir System Prompt": {
      "main": [
        [
          {
            "node": "AI Agent (Fenrir)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent (Fenrir)": {
      "main": [
        [
          {
            "node": "Format Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch": {
      "main": [
        [
          {
            "node": "Set Fenrir System Prompt",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Set Corvus System Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Formulario": {
      "main": [
        [
          {
            "node": "Preparar",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Preparar": {
      "main": [
        [
          {
            "node": "Gerar Embedding",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gerar Embedding": {
      "main": [
        [
          {
            "node": "Montar",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Montar": {
      "main": [
        [
          {
            "node": "Salvar Supabase",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Vision Gate": {
      "main": [
        [
          {
            "node": "Vision Analyzer",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Vision Analyzer": {
      "main": [
        [
          {
            "node": "Vision Context Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Vision Context Merge": {
      "main": [
        [
          {
            "node": "Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1",
    "availableInMCP": false
  },
  "versionId": "276e754b-8d48-4f9b-a47b-c49588819ffc",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "-RHh35RswKnZKVt1aO9zc",
  "tags": []
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Corvus — Ingestão via Formulário. Uses agent, lmChatOpenAi, vectorStoreSupabase, embeddingsOpenAi. Webhook trigger; 25 nodes.

Source: https://github.com/T4Msy/Corvus-2.0/blob/main/n8n/workflow.json — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

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

AI & RAG

Hi! I’m Amanda, a creator of intelligent automations using n8n and Make. I’ve been building AI-powered workflows for over 2 years, always focused on usability and innovation. This one here is very spe

OpenAI Chat, Redis, OpenAI +11
AI & RAG

HeyDinastia. Uses executeCommand, httpRequest, youTube, postgres. Webhook trigger; 66 nodes.

Execute Command, HTTP Request, YouTube +15
AI & RAG

This workflow automates multi-channel AI-driven sales engagement for lead qualification, service information delivery, and consultation booking. It integrates WhatsApp, Facebook Messenger, Instagram D

Agent, OpenAI Embeddings, OpenAI Chat +11
AI & RAG

Agente_Atendimento_E_commerce. Uses baserow, redis, openAi, httpRequest. Webhook trigger; 52 nodes.

Baserow, Redis, OpenAI +9
AI & RAG

Corvus 3.2 Beta. Uses httpRequest, agent, lmChatOpenAi, vectorStoreSupabase. Webhook trigger; 48 nodes.

HTTP Request, Agent, OpenAI Chat +5