{
  "name": "Asistente de preguntas internas con fuente citada (plano de Saphia Labs)",
  "nodes": [
    {
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "id": "tt",
      "name": "Telegram Trigger",
      "type": "n8n-nodes-base.telegramTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        0
      ],
      "webhookId": "saphia-preguntas"
    },
    {
      "parameters": {
        "jsCode": "const m = $json.message || {};\nreturn [{ json: { pregunta: String(m.text || '').trim(), chatId: String((m.chat || {}).id || ''), body: { query: String(m.text || '').slice(0, 100), filter: { value: 'page', property: 'object' }, page_size: 5 } } }];"
      },
      "id": "q",
      "name": "Code: pregunta",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        260,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.notion.com/v1/search",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "notionApi",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json.body) }}",
        "options": {}
      },
      "id": "ns",
      "name": "Notion: buscar",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        520,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "// Solo documentos bajo la página de documentos internos (no todo el espacio)\nconst PERMITIDO = 'TU_PAGINA_DOCUMENTOS_ID'.replace(/-/g, '');\nconst res = ($json.results || []).filter(p => (p.parent?.page_id || '').replace(/-/g, '') === PERMITIDO).slice(0, 3);\nif (!res.length) return [{ json: { id: '', titulo: '', url: '' } }];\nreturn res.map(p => { const t = Object.values(p.properties||{}).find(v=>v.type==='title'); return { json: { id: p.id, titulo: t ? t.title.map(x=>x.plain_text).join('') : '', url: p.url } }; });"
      },
      "id": "top",
      "name": "Code: 3 documentos",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        780,
        0
      ]
    },
    {
      "parameters": {
        "url": "=https://api.notion.com/v1/blocks/{{ $json.id }}/children?page_size=100",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "notionApi",
        "options": {}
      },
      "id": "nb",
      "name": "Notion: contenido",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1040,
        0
      ],
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jsCode": "const docs = $('Code: 3 documentos').all();\nconst frags = $input.all().map((it, i) => { const d = docs[i] ? docs[i].json : {}; const texto = (it.json.results || []).map(b => { const rt = (b[b.type] || {}).rich_text || []; return rt.map(x => x.plain_text).join(''); }).filter(Boolean).join('\\n').slice(0, 4000); return d.titulo ? `### ${d.titulo}\\n${d.url}\\n${texto}` : ''; }).filter(Boolean);\nreturn [{ json: { pregunta: $('Code: pregunta').first().json.pregunta, chatId: $('Code: pregunta').first().json.chatId, fragmentos: frags.length ? frags.join('\\n\\n') : '(ningún documento coincide)' } }];"
      },
      "id": "frag",
      "name": "Code: fragmentos",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1300,
        0
      ]
    },
    {
      "parameters": {
        "resource": "text",
        "operation": "message",
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "claude-sonnet-5-5"
        },
        "messages": {
          "values": [
            {
              "role": "user",
              "content": "={{ 'PREGUNTA\\n' + $json.pregunta + '\\n\\nFRAGMENTOS\\n' + $json.fragmentos }}"
            }
          ]
        },
        "options": {
          "system": "Eres el asistente interno de [organización]. Recibes una pregunta y fragmentos de documentos oficiales (cada uno con título y enlace). Responde en máximo 5 líneas usando SOLO esos fragmentos:\n- Primero la respuesta directa.\n- Luego la cita textual entre comillas y el título del documento con su enlace.\n- Si los fragmentos no responden la pregunta, escribe exactamente: \"No está en los documentos que puedo consultar. Lo escalo a [responsable].\"\nReglas: no completes con conocimiento general; si dos documentos se contradicen, dilo y cita ambos; trato de tú; sin opiniones.",
          "maxTokens": 4000
        }
      },
      "id": "cl",
      "name": "Claude: responder con cita",
      "type": "@n8n/n8n-nodes-langchain.anthropic",
      "typeVersion": 1,
      "position": [
        1560,
        0
      ]
    },
    {
      "parameters": {
        "chatId": "={{ $('Code: fragmentos').first().json.chatId }}",
        "text": "={{ ($json.content || []).filter(b => b.type === 'text').map(b => b.text).join('\\n').trim() }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "id": "tg",
      "name": "Telegram: responder",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        1820,
        0
      ]
    }
  ],
  "connections": {
    "Telegram Trigger": {
      "main": [
        [
          {
            "node": "Code: pregunta",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code: pregunta": {
      "main": [
        [
          {
            "node": "Notion: buscar",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notion: buscar": {
      "main": [
        [
          {
            "node": "Code: 3 documentos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code: 3 documentos": {
      "main": [
        [
          {
            "node": "Notion: contenido",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notion: contenido": {
      "main": [
        [
          {
            "node": "Code: fragmentos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code: fragmentos": {
      "main": [
        [
          {
            "node": "Claude: responder con cita",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude: responder con cita": {
      "main": [
        [
          {
            "node": "Telegram: responder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "timezone": "America/Bogota"
  },
  "meta": {
    "templateCredsSetupCompleted": false,
    "probadoEn": "n8n 2.41.6, octubre 2026",
    "preparacion": "En Notion, crea una página \"Documentos internos\" compartida con tu integración y pon debajo los documentos oficiales (una página por documento). Reemplaza TU_PAGINA_DOCUMENTOS_ID en el nodo \"Code: 3 documentos\" y el [responsable] en el prompt. El Telegram Trigger necesita WEBHOOK_URL pública para recibir mensajes.",
    "fuente": "https://saphialabs.com/recursos/flujos/#f7"
  }
}