{
  "nodes": [
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.perplexity.ai/chat/completions",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "perplexityApi",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"model\": \"sonar\",\n  \"messages\": [\n    {\n      \"role\": \"system\",\n      \"content\": \"You are a research assistant gathering current information about political events. Provide factual, detailed context with sources. Include key dates, actors, decisions, and statements from multiple perspectives.\"\n    },\n    {\n      \"role\": \"user\",\n      \"content\": {{ JSON.stringify($json.chatInput + \"\\n\\nProvide comprehensive context about this question including:\\n- Recent news and developments\\n- Key actors and their positions\\n- Timeline of events\\n- Multiple perspectives\\n- Credible sources\") }}\n    }\n  ],\n  \"temperature\": 0.3,\n  \"max_tokens\": 2000,\n  \"return_citations\": true,\n  \"return_images\": false,\n  \"search_recency_filter\": \"month\"\n}\n",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          },
          "timeout": 30000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        272,
        64
      ],
      "id": "feb76558-5a1e-4c73-be84-ccc3cca4c392",
      "name": "Get Current News Context",
      "retryOnFail": true,
      "credentials": {
        "perplexityApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=CURRENT EVENT CONTEXT (from Perplexity):\n{{ $('Get Current News Context').item.json.choices[0].message.content }}\n\nNEWS SOURCES:\n{{ $('Get Current News Context').item.json.citations ? $('Get Current News Context').item.json.citations.join('\\n') : 'No citations available' }}\n\nUSER QUESTION:\n{{ $('Normalize Input').item.json.chatInput }}\n\nProvide a comprehensive political science analysis.",
        "options": {
          "systemMessage": "=You are an expert political scientist with deep knowledge of comparative politics, electoral systems, democratization, authoritarianism, political institutions, social movements, and international relations.\n\nWORKFLOW:\n1. You will receive CURRENT EVENT CONTEXT from Perplexity API (recent news articles)\n2. You will receive the USER'S QUESTION\n3. Use your MCP tools (OpenAlex) to search academic literature for:\n   - Relevant political science theories and frameworks\n   - Historical precedents and comparative case studies\n   - Empirical research findings across regions\n   - Regional and area studies expertise when relevant\n\n4. Synthesize a comprehensive analysis that:\n   - Summarizes the current situation (from news context)\n   - Applies relevant theoretical frameworks (from academic research)\n   - Cites historical precedents and comparative cases (from MCP tools)\n   - Provides evidence-based strategic assessment\n   - Acknowledges uncertainties, competing perspectives, and limitations\n\n5. ALWAYS cite sources properly:\n   - News: [Source name from Perplexity]\n   - Academic: [Author(s) Year, Journal/Publisher, DOI if available]\n\n6. Structure your response with clear sections:\n  - Key Takeaways (So-What) - 3\u20137 bullets with the most consequential insights; no background.\n- Signals to Watch - Leading + lagging indicators, what movement would confirm/deny your view.\n- Implications by Stakeholder - Government, opposition, public sentiment, markets/IOs; concise, impact-oriented.\n- Near-Term Scenarios (2\u20136 weeks) - 2\u20134 plausible paths with calibrated probabilities (sum \u2248 100%).\n- Risks & Uncertainties - Top 3\u20135 risk factors; specify unknowns and data that would reduce uncertainty.\n- Recommended Options - 2\u20134 actions with pros/cons, prerequisites, and likely second-order effects.\n- Monitoring Plan - Concrete items to track (events, metrics, statements), with expected thresholds.\n\n\n\n\nTOOLS AVAILABLE (OpenAlex MCP):\n- search_works: Search scholarly works by keywords, concepts, topics\n- search_authors: Find scholars by name, institution, research area, country\n- retrieve_author_works: Get all publications by a specific author\n- autocomplete_authors: Disambiguate author names and affiliations\n- filter_by_institution: Find research from specific universities/think tanks\n- filter_by_country: Find research from specific countries or regions\n\nRESEARCH STRATEGY:\n- Start broad: Search for general theories and frameworks\n- Then narrow: Search for regional cases, country-specific studies\n- Use author search to find area experts (e.g., scholars at regional universities)\n- Cross-reference multiple sources before drawing conclusions\n- Acknowledge when literature is sparse for specific regions or topics\n\nUse multiple tools strategically to build comprehensive, globally-informed analysis. Ground all claims in peer-reviewed evidence.\n"
        }
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 2.2,
      "position": [
        496,
        64
      ],
      "id": "4961fcb3-3c4b-4d23-a241-3e80efcb48d9",
      "name": "Political Science Expert"
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o"
        },
        "options": {
          "maxTokens": 4000,
          "temperature": 0.4
        }
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.2,
      "position": [
        512,
        288
      ],
      "id": "41ca7561-5663-4661-9d49-d13fb4a335ab",
      "name": "OpenAI Chat Model",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Get data from previous nodes\nconst aiOutput = $input.item.json;\nconst aiResponse =\n  aiOutput.output ||\n  aiOutput.text ||\n  aiOutput.response ||\n  \"No analysis generated\";\nconst perplexityData = $(\"Get Current News Context\").item.json;\nconst userQuestion = $(\"Normalize Input\").item.json.chatInput;\n\n// Extract citations safely\nlet citations = [];\nif (perplexityData.citations && Array.isArray(perplexityData.citations)) {\n  citations = perplexityData.citations;\n}\n\n// Extract token usage if available\nlet tokenUsage = {};\nif (perplexityData.usage) {\n  tokenUsage.perplexity = perplexityData.usage;\n}\n\n// Format the response\nconst formattedResponse = {\n  question: userQuestion,\n  analysis: aiResponse,\n  metadata: {\n    news_sources: citations,\n    timestamp: new Date().toISOString(),\n    model: \"gpt-4o\",\n    mcp_tools_used: [\"OpenAlex (250M+ scholarly works, citations, authors)\"],\n    perplexity_model:\n      perplexityData.model || \"llama-3.1-sonar-large-128k-online\",\n    token_usage: tokenUsage,\n  },\n};\n\n// Return formatted data\nreturn [\n  {\n    json: formattedResponse,\n  },\n];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        848,
        64
      ],
      "id": "d9b14afb-bb12-4bb8-9d5e-1f9de5fd85b2",
      "name": "Format Analysis"
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "={{ $json.analysis }}",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        1072,
        64
      ],
      "id": "a392c90c-d293-40fc-a6ba-fcb0dfb1d38b",
      "name": "Send Analysis to User"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-mcp.mcpClientTool",
      "typeVersion": 1,
      "position": [
        640,
        288
      ],
      "id": "d7cbe794-4557-41ba-841e-276a3aeae893",
      "name": "OpenAlex Server",
      "credentials": {
        "mcpClientApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "chat/ad221486-cf3d-43e0-98b2-390192147713",
        "responseMode": "responseNode",
        "options": {
          "allowedOrigins": "*"
        }
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        -176,
        64
      ],
      "id": "934b6f11-94d4-4189-8f3f-dd78bb43f1ef",
      "name": "Webhook"
    },
    {
      "parameters": {
        "jsCode": "// Normalizes incoming payloads (JSON, form, plain text) into\n// { chatInput, history, auth_user_id, threadId, client:{} }\n// so downstream nodes receive consistent structures.\n\nconst headers = $json.headers ?? {};\nconst ct = String(\n  headers[\"content-type\"] || headers[\"Content-Type\"] || \"\"\n).toLowerCase();\n\nconst body = $json.body ?? {};\nconst query = $json.query ?? {};\nlet chatInput = \"\";\n\n// Helper to pluck a prompt-like field from an object\nconst pick = (source) => {\n  if (!source || typeof source !== \"object\") return \"\";\n  return (\n    source.chatInput ??\n    source.message ??\n    source.text ??\n    source.q ??\n    source.prompt ??\n    \"\"\n  );\n};\n\nif (ct.includes(\"application/json\")) {\n  chatInput = pick(body);\n} else if (\n  ct.includes(\"application/x-www-form-urlencoded\") ||\n  ct.includes(\"multipart/form-data\")\n) {\n  chatInput = pick(body);\n} else if (ct.includes(\"text/plain\")) {\n  chatInput = String($json.body ?? \"\").trim();\n}\n\nif (!chatInput) chatInput = pick(query);\nif (!chatInput) chatInput = String($json.chatInput ?? \"\").trim();\n\nchatInput = String(chatInput || \"\").trim();\nif (!chatInput) {\n  return [{ json: { error: \"Missing chatInput\", received: $json } }];\n}\n\n// Normalize optional history array\nconst rawHistory = Array.isArray(body.history)\n  ? body.history\n  : Array.isArray(query.history)\n    ? query.history\n    : Array.isArray($json.history)\n      ? $json.history\n      : [];\n\nconst history = rawHistory\n  .filter((entry) => entry && typeof entry.content === \"string\")\n  .map((entry) => ({\n    role: entry.role === \"assistant\" ? \"assistant\" : \"user\",\n    content: entry.content.trim(),\n  }))\n  .filter((entry) => entry.content.length > 0);\n\nconst authUserId =\n  body.auth_user_id ??\n  query.auth_user_id ??\n  headers[\"x-auth-user-id\"] ??\n  headers[\"X-Auth-User-Id\"] ??\n  ($json.auth_user_id ?? null);\n\nconst threadId =\n  body.threadId ??\n  query.threadId ??\n  headers[\"x-thread-id\"] ??\n  headers[\"X-Thread-Id\"] ??\n  null;\n\nreturn [\n  {\n    json: {\n      chatInput,\n      history,\n      auth_user_id: typeof authUserId === \"string\" ? authUserId : null,\n      threadId,\n      client: {\n        ip:\n          headers[\"x-forwarded-for\"] ??\n          headers[\"X-Forwarded-For\"] ??\n          headers[\"cf-connecting-ip\"] ??\n          headers[\"CF-Connecting-IP\"] ??\n          null,\n        ua: headers[\"user-agent\"] ?? headers[\"User-Agent\"] ?? null,\n        origin: headers.origin ?? headers.Origin ?? null,\n        referer: headers.referer ?? headers.Referer ?? null,\n      },\n    },\n  },\n];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        48,
        64
      ],
      "id": "c358f2d4-8201-4bf4-8511-5dcfe21da6d4",
      "name": "Normalize Input"
    }
  ],
  "connections": {
    "Get Current News Context": {
      "main": [
        [
          {
            "node": "Political Science Expert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Political Science Expert": {
      "main": [
        [
          {
            "node": "Format Analysis",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Political Science Expert",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Format Analysis": {
      "main": [
        [
          {
            "node": "Send Analysis to User",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAlex Server": {
      "ai_tool": [
        [
          {
            "node": "Political Science Expert",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Webhook": {
      "main": [
        [
          {
            "node": "Normalize Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Input": {
      "main": [
        [
          {
            "node": "Get Current News Context",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "meta": {
    "templateCredsSetupCompleted": true
  }
}