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 →
{
"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.
openAiApipostgressupabaseApi
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 →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
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
HeyDinastia. Uses executeCommand, httpRequest, youTube, postgres. Webhook trigger; 66 nodes.
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
Agente_Atendimento_E_commerce. Uses baserow, redis, openAi, httpRequest. Webhook trigger; 52 nodes.
Corvus 3.2 Beta. Uses httpRequest, agent, lmChatOpenAi, vectorStoreSupabase. Webhook trigger; 48 nodes.