{
  "id": "oSwN9ry7V8KSNbcr",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Contextual AI Agent Orchestration",
  "tags": [],
  "nodes": [
    {
      "id": "3fc78343-dd47-4b2a-926c-f366c47fd1cc",
      "name": "Create Agent",
      "type": "n8n-nodes-contextualai.contextualAi",
      "position": [
        288,
        112
      ],
      "parameters": {
        "agentName": "={{ $('Submit Agent Information').item.json['Agent Name'] }}",
        "datastoreName": "={{ $('Submit Agent Information').item.json['Datastore Name'] }}",
        "agentDescription": "={{ $('Submit Agent Information').item.json['Agent Description'] }}",
        "binaryPropertyName": "={{ $json.binaryKeys }}"
      },
      "credentials": {
        "contextualAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "9afd4c74-47cc-4ecf-ab7b-ef7df2e3d88b",
      "name": "Submit Agent Information",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        -160,
        112
      ],
      "parameters": {
        "options": {},
        "formTitle": "Create your AI Agent",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Agent Name",
              "placeholder": "e.g. Customer Support Bot, Research Assistant, or Code Reviewer",
              "requiredField": true
            },
            {
              "fieldLabel": "Agent Description",
              "placeholder": "e.g. An AI assistant that helps answer customer questions and summarize responses.",
              "requiredField": true
            },
            {
              "fieldLabel": "Datastore Name",
              "placeholder": "e.g. support_knowledge_base, research_docs, or company_manuals",
              "requiredField": true
            },
            {
              "fieldType": "file",
              "fieldLabel": "Files",
              "requiredField": true,
              "acceptFileTypes": ".pdf, .docx, .doc, .ppt"
            }
          ]
        },
        "formDescription": "Configure your personalized AI agent by providing the essential details below. Once submitted, it will automatically create an agent for you"
      },
      "typeVersion": 2.3
    },
    {
      "id": "f0cae1d6-6af5-4d06-90d4-e754e7bd4d22",
      "name": "Preprocessing Step",
      "type": "n8n-nodes-base.code",
      "position": [
        64,
        112
      ],
      "parameters": {
        "jsCode": "const item = $input.first(); \nconst binaries = item.binary;\nconst keys = Object.keys(binaries);\n\nreturn [\n  {\n    json: {\n      binaryKeys: keys.join(', ')\n    },\n    binary: binaries\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "db104ab2-8ccb-4ab0-aca1-88ed528e539f",
      "name": "Agent Orchestrator",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        192,
        448
      ],
      "parameters": {
        "options": {
          "systemMessage": "You can use two Contextual AI tools: list_agents (to get agent names and IDs) and query (to ask an agent).\nFor each user query:\n\nIf an agent name is given, call list_agents, find the matching agent ID, and use it.\n\nIf no name is given, call list_agents, pick the most relevant agent by intent.\n\nCall query with that agent ID and the user\u2019s question.\n\nReturn the response grounded in the response from query tool.\n"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "58ad8395-3866-4cf2-a101-c4e6dd24186a",
      "name": "Chat",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        -160,
        448
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1.3
    },
    {
      "id": "37877c08-6529-4b48-a039-b4ccc8128231",
      "name": "Google Gemini Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        32,
        672
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "96aa07fe-7b74-41ea-af24-41c0aaeb11e1",
      "name": "Simple Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        192,
        672
      ],
      "parameters": {
        "contextWindowLength": 10
      },
      "typeVersion": 1.3
    },
    {
      "id": "6da227ee-1f51-447a-b13e-23ae53cdbd5b",
      "name": "Query Agent Tool",
      "type": "n8n-nodes-contextualai.contextualAiTool",
      "position": [
        336,
        672
      ],
      "parameters": {
        "query": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Query', ``, 'string') }}",
        "agentId": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Agent_ID', ``, 'string') }}",
        "resource": "Query"
      },
      "credentials": {
        "contextualAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "212f4d81-bc46-4ee3-afa9-debfb6dca484",
      "name": "List Agents Tool",
      "type": "n8n-nodes-contextualai.contextualAiTool",
      "position": [
        480,
        672
      ],
      "parameters": {
        "operation": "List Agents"
      },
      "credentials": {
        "contextualAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "b4e66a87-4f35-4b62-80d8-2973d478d5c8",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -736,
        -144
      ],
      "parameters": {
        "width": 480,
        "height": 1312,
        "content": "# RAG Multi-Agent Orchestration with Contextual AI Query Tool and Gemini 2.5 Flash\n\n## PROBLEM  \nManaging multiple RAG AI agents can be complex when each has its own purpose and vector database.  \n- Manually tracking agents and deciding which one to query wastes time.  \n- LLMs often struggle to determine which agent best fits a user\u2019s request.  \n\n### This workflow enables automated multi-agent orchestration, dynamically selecting and querying the correct agent using Contextual AI Query Tool and Gemini 2.5 Flash.  \n\n## How it works  \n- A **form trigger** allows users to create new agents by specifying a name, description, datastore, and uploading files.  \n- A new agent is created with the provided information and files are ingested in the datastore\n- We get the status of file ingestion every 30 seconds until the ingestion process is complete\n- When users send queries, the **Agent Orchestrator** identifies the most relevant agent to generate grounded, context-aware responses.  \n\n**Note:** The document ingestion process is asynchronous and may take a few minutes before your agent has the document fully available in the datastore for querying.\n\n## How to set up  \n- Create a free [Contextual AI account](https://app.contextual.ai/) and obtain your `CONTEXTUALAI_API_KEY`.  \n- Add `CONTEXTUALAI_API_KEY` as an **environment variable** in n8n. \n- For the baseline model, we have used Gemini 2.5 Flash Model, you can find your Gemini API key[ here](https://ai.google.dev/gemini-api/docs/api-key) \n\n\n## How to customize the workflow  \n- Replace the **Form Trigger** with a **Webhook Trigger** or manual input to integrate with custom systems.  \n- Swap **Gemini 2.5 Flash** with another LLM provider\n- Update the wait time as per user requirement\n- Modify the system prompt to fine-tune how the orchestration logic selects and queries agents.  \n- You can check out this [Contextual AI API reference](https://docs.contextual.ai/api-reference/agents/create-agent) for more details on agent creation and usage.  \n- If you have feedback or need support, please email **feedback@contextual.ai**.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "96446a81-d558-4261-8f00-28678d5baa20",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -224,
        -144
      ],
      "parameters": {
        "color": 7,
        "width": 1808,
        "height": 448,
        "content": "### 1: Form Submission  \nUsers submit a form to create a new RAG agent by providing the **agent name**, **description**, **datastore name** and uploading relevant **documents**. Then, we iterate over each files to check their ingestion status. The workflow completes when both files are ingested and agent is ready for query.\n\n**Note:** The document ingestion process is asynchronous and may take a few minutes before your agent has the document fully available in the datastore for querying.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "96195bc9-9ede-45eb-8c26-60a8bf46cee3",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -224,
        320
      ],
      "parameters": {
        "color": 7,
        "width": 992,
        "height": 496,
        "content": "### Step 2: Query and Retrieval  \nUsers can enter a query, and the workflow automatically identifies the most relevant RAG agent based on the query and provides users with grounded answers.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "7a94b05a-46ff-4b54-be80-c8038ca7052e",
      "name": "Split Out",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        512,
        112
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "uploaded"
      },
      "typeVersion": 1
    },
    {
      "id": "1d2b3eab-8937-4f20-9619-994cfa711a59",
      "name": "Wait",
      "type": "n8n-nodes-base.wait",
      "position": [
        960,
        48
      ],
      "parameters": {
        "amount": 30
      },
      "typeVersion": 1.1
    },
    {
      "id": "a32883c4-bee5-4922-854c-b4a3ae25226d",
      "name": "If",
      "type": "n8n-nodes-base.if",
      "position": [
        1408,
        112
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "e53d6b6e-da22-40c3-8445-339cd867e1e6",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.metadata.parseJson().status }}",
              "rightValue": "completed"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "4c41e78c-2c4b-4bd7-94a3-278d4335f086",
      "name": "Iterate over each files",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        736,
        112
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "b48205ed-227d-468f-88e6-e7da8230427a",
      "name": "Get Document Ingestion Status",
      "type": "n8n-nodes-contextualai.contextualAi",
      "position": [
        1184,
        -32
      ],
      "parameters": {
        "resource": "Datastore",
        "operation": "Get Document Metadata",
        "documentId": "={{ $json.documentId }}",
        "datastoreId": "={{ $('Create Agent').item.json.datastoreIds[0] }}"
      },
      "credentials": {
        "contextualAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "25d222d7-7c79-49a1-a1e0-431e7e0839c4",
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "Iterate over each files",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Chat": {
      "main": [
        [
          {
            "node": "Agent Orchestrator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait": {
      "main": [
        [
          {
            "node": "Get Document Ingestion Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out": {
      "main": [
        [
          {
            "node": "Iterate over each files",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Agent": {
      "main": [
        [
          {
            "node": "Split Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Simple Memory": {
      "ai_memory": [
        [
          {
            "node": "Agent Orchestrator",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "List Agents Tool": {
      "ai_tool": [
        [
          {
            "node": "Agent Orchestrator",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Query Agent Tool": {
      "ai_tool": [
        [
          {
            "node": "Agent Orchestrator",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Preprocessing Step": {
      "main": [
        [
          {
            "node": "Create Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Iterate over each files": {
      "main": [
        [],
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Agent Orchestrator",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Submit Agent Information": {
      "main": [
        [
          {
            "node": "Preprocessing Step",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Document Ingestion Status": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}