{
  "updatedAt": "2025-12-11T16:44:19.000Z",
  "createdAt": "2025-10-27T18:25:38.997Z",
  "id": "eQO1bX8fadDwNvMu",
  "name": "call_assi",
  "active": true,
  "isArchived": false,
  "nodes": [
    {
      "parameters": {
        "jsCode": "const phoneNumber = $input.first().json.body.message.call?.customer?.number ?? $input.first().json.body.message.toolCalls[0].function.arguments.phoneNumber\n  \nreturn {phoneNumber}"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        0,
        0
      ],
      "id": "495db161-4b96-492a-9ad0-86dc38369866",
      "name": "Get phone number",
      "disabled": true
    },
    {
      "parameters": {
        "description": "This tool's purpose is to cancel an appointment",
        "workflowId": {
          "__rl": true,
          "value": "qJMnBdEthjId0vbd",
          "mode": "list",
          "cachedResultUrl": "/workflow/qJMnBdEthjId0vbd",
          "cachedResultName": "cancel_appointment"
        },
        "workflowInputs": {
          "mappingMode": "defineBelow",
          "value": {
            "appointmentId": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('appointmentId', ``, 'string') }}"
          },
          "matchingColumns": [
            "appointmentId"
          ],
          "schema": [
            {
              "id": "appointmentId",
              "displayName": "appointmentId",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "string",
              "removed": false
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        }
      },
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "typeVersion": 2.2,
      "position": [
        528,
        416
      ],
      "id": "f39f200d-f7a5-4115-8836-4fadf45f9b4c",
      "name": "cancelAppointment"
    },
    {
      "parameters": {
        "description": "This tool's purpose is to reschedule the appointment for the user",
        "workflowId": {
          "__rl": true,
          "value": "i4ywe4sK8CvhockA",
          "mode": "list",
          "cachedResultUrl": "/workflow/i4ywe4sK8CvhockA",
          "cachedResultName": "reschedule_appointment"
        },
        "workflowInputs": {
          "mappingMode": "defineBelow",
          "value": {
            "appointmentId": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('appointmentId', ``, 'string') }}",
            "appointmentDate": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('appointmentDate', ``, 'string') }}"
          },
          "matchingColumns": [],
          "schema": [
            {
              "id": "appointmentId",
              "displayName": "appointmentId",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "string"
            },
            {
              "id": "appointmentDate",
              "displayName": "appointmentDate",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "string"
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        }
      },
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "typeVersion": 2.2,
      "position": [
        688,
        416
      ],
      "id": "85f58800-5a87-4328-b9d4-1410e947aee6",
      "name": "rescheduleAppointment"
    },
    {
      "parameters": {
        "description": "This tool will be responsible for booking a new appointment in the calendar",
        "workflowId": {
          "__rl": true,
          "value": "RIvTGcIIx3zSsHiZ",
          "mode": "list",
          "cachedResultUrl": "/workflow/RIvTGcIIx3zSsHiZ",
          "cachedResultName": "bookAppointment"
        },
        "workflowInputs": {
          "mappingMode": "defineBelow",
          "value": {
            "appointmentStartTime": "={{ $json.body.message.toolCallList[0].function.arguments.preferredTime }}",
            "firstName": "={{ $json.body.message.toolCallList[0].function.arguments.firstName }}",
            "lastName": "={{ $json.body.message.toolCallList[0].function.arguments.lastName }}",
            "phoneNumber": "={{ $json.body.message.toolCallList[0].function.arguments.phoneNumber }}"
          },
          "matchingColumns": [],
          "schema": [
            {
              "id": "appointmentStartTime",
              "displayName": "appointmentStartTime",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "string"
            },
            {
              "id": "firstName",
              "displayName": "firstName",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "string"
            },
            {
              "id": "lastName",
              "displayName": "lastName",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "string"
            },
            {
              "id": "phoneNumber",
              "displayName": "phoneNumber",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "string"
            },
            {
              "id": "email",
              "displayName": "email",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "string",
              "removed": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        }
      },
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "typeVersion": 2.2,
      "position": [
        848,
        416
      ],
      "id": "9c11a3ce-7d89-46d1-af88-21ec1327ef29",
      "name": "bookAppointment"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=You are assisting with appointment scheduling.\n\nInput:\n- toolCallName\n- preferredTime\n- firstName\n- lastName\n- appointmentId\n- appointmentDate\n\nOutput:\nReturn only JSON specifying what action to perform, using the provided arguments. No explanation.\n",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 2,
      "position": [
        320,
        192
      ],
      "id": "b85bb6f9-2cbf-44e2-a765-cf5b507b1030",
      "name": "AI Agent1",
      "executeOnce": false
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "e0eb2929-3f5d-48ea-ba3c-cec29f87010c",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        -304,
        176
      ],
      "id": "cc500a08-b6fc-4f42-8664-3336608981b9",
      "name": "Webhook1",
      "executeOnce": false
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={\n  \"results\": [\n    {\n      \"toolCallId\": \"{{ $('Webhook1').item.json.body.message.toolCalls[0].id }}\",\n      \"result\": \"{{ $json.output.replaceAll(\"\\n\", \"\").replace(/\"([^\"]+)\"/g, '\\\\\"$1\\\\\"') }}\"\n    }\n  ]\n}\n",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        864,
        176
      ],
      "id": "4382f5fa-8815-4d95-a1e2-62f1a5e8d887",
      "name": "Respond to Webhook"
    },
    {
      "parameters": {
        "description": "This tool will check for available timeslots and return their start time",
        "workflowId": {
          "__rl": true,
          "value": "25L7BjNxaV3gQnx0",
          "mode": "list",
          "cachedResultUrl": "/workflow/25L7BjNxaV3gQnx0",
          "cachedResultName": "getAvailability"
        },
        "workflowInputs": {
          "mappingMode": "defineBelow",
          "value": {
            "startTime": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('startTime', ``, 'string') }}",
            "endTime": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('endTime', ``, 'string') }}"
          },
          "matchingColumns": [],
          "schema": [
            {
              "id": "startTime",
              "displayName": "startTime",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "string"
            },
            {
              "id": "endTime",
              "displayName": "endTime",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "string"
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        }
      },
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "typeVersion": 2.2,
      "position": [
        304,
        400
      ],
      "id": "b3923ed8-896b-4a17-840c-3d985fbab81c",
      "name": "getAvailability"
    },
    {
      "parameters": {
        "description": "This tool will retrieve the existing appointment for the patient",
        "workflowId": {
          "__rl": true,
          "value": "zZLxKOn5DyLfS8Ho",
          "mode": "list",
          "cachedResultUrl": "/workflow/zZLxKOn5DyLfS8Ho",
          "cachedResultName": "getAppointment"
        },
        "workflowInputs": {
          "mappingMode": "defineBelow",
          "value": {
            "appointmentId": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('appointmentId', ``, 'string') }}"
          },
          "matchingColumns": [],
          "schema": [
            {
              "id": "appointmentId",
              "displayName": "appointmentId",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "canBeUsedToMatch": true,
              "type": "string",
              "removed": false
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        }
      },
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "typeVersion": 2.2,
      "position": [
        416,
        400
      ],
      "id": "a5281f99-3f80-4108-961b-c60ea8b1be9f",
      "name": "getAppointment"
    },
    {
      "parameters": {
        "modelName": "models/gemini-2.0-flash-001",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "typeVersion": 1,
      "position": [
        160,
        416
      ],
      "id": "dc85af03-53d2-44cc-bfec-dd05b8508b74",
      "name": "Google Gemini Chat Model",
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// n8n Function node \u2014 \"filter + map\" for Vapi \u2192 AI Agent integration\n// Returns a compact, safe object with all the template variables your prompt expects.\n//\n// Paste this into an n8n Function node. It expects the incoming webhook JSON at $json\n// and returns one item: item.json contains the mapped fields.\n\nconst body = $json[\"body\"] || {};\nconst message = body.message || {};\n\n// Helper: find the toolCall in multiple possible places\nconst toolCall =\n  (message.toolCalls && message.toolCalls[0]) ||\n  (message.toolCallList && message.toolCallList[0]) ||\n  (message.toolWithToolCallList && message.toolWithToolCallList[0] && message.toolWithToolCallList[0].toolCall) ||\n  null;\n\n// Safe parser for possibly stringified arguments\nfunction parseArgs(raw) {\n  if (!raw) return {};\n  if (typeof raw === \"object\") return raw;\n  if (typeof raw === \"string\") {\n    try {\n      return JSON.parse(raw);\n    } catch (e) {\n      // fallback: simple key=value pairs or raw string\n      return { rawString: raw };\n    }\n  }\n  return {};\n}\n\n// Find last user message (best-effort)\nfunction findLastUserMessage(artifact, messageFallback) {\n  if (!artifact) return messageFallback || \"\";\n  const msgs = artifact.messagesOpenAIFormatted || artifact.messages || [];\n  for (let i = msgs.length - 1; i >= 0; i--) {\n    const m = msgs[i];\n    if (!m) continue;\n    // support both formats: {role, content} and {role, message}\n    const role = (m.role || \"\").toString().toLowerCase();\n    const text = m.content || m.message || \"\";\n    if (role === \"user\" || role === \"human\") return text;\n    // fallback heuristics: treat any item with content and not system as user\n    if (text && role && role !== \"system\" && role !== \"assistant\") return text;\n  }\n  return messageFallback || \"\";\n}\n\nconst args = parseArgs(toolCall && toolCall.function && toolCall.function.arguments);\nconst toolName = (toolCall && ((toolCall.function && toolCall.function.name) || toolCall.name)) || null;\n\nconst artifact = message.artifact || {};\nconst lastUserMessage = findLastUserMessage(artifact, message.text || message.message || \"\");\n\n// Heuristics for name and phone if not provided explicitly\nlet firstName = args.firstName || null;\nlet lastName = args.lastName || null;\nlet fullName = args.name || args.fullName || null;\nlet phone = args.phoneNumber || args.mobile || args.phone || null;\n\nif (!fullName && lastUserMessage) {\n  const nameMatch = lastUserMessage.match(/(?:for|booking for|new booking for|book)\\s+([A-Z][a-z]+(?:\\s[A-Z][a-z]+)*)/i);\n  if (nameMatch) fullName = nameMatch[1];\n}\n\nif (!phone && lastUserMessage) {\n  const phoneMatch = lastUserMessage.match(/(\\+?\\d[\\d\\-\\s]{7,}\\d)/);\n  if (phoneMatch) phone = phoneMatch[0].replace(/\\s+/g, \"\");\n}\n\n// split fullName into first/last if needed\nif (!firstName && fullName) {\n  const parts = fullName.trim().split(/\\s+/);\n  firstName = parts[0] || null;\n  lastName = parts.length > 1 ? parts.slice(1).join(\" \") : (lastName || null);\n}\n\n// Map all expected template variables (keep nulls if missing)\nconst mapped = {\n  toolCallName: toolName,\n  firstName: firstName || null,\n  lastName: lastName || null,\n  preferredTime: args.preferredTime || null,\n  appointmentTime: args.appointmentTime || null,\n  appointmentReason: args.appointmentReason || null,\n  birthDate: args.birthDate || null,\n  fullName: fullName || null,\n  appointmentDate: args.appointmentDate || null,\n  appointmentId: args.appointmentId || null,\n  lastUserMessage,\n  phoneNumber: phone || null,\n  chatId: (body.chat && body.chat.id) || (body.chatId || null),\n  // Debugging / telemetry (optional)\n  _originalSizeBytes: Buffer.from(JSON.stringify($json)).length,\n  _toolCallRawId: toolCall && toolCall.id ? toolCall.id : null,\n};\n\n// Return the compact mapped object\nreturn [{ json: mapped }];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -16,
        192
      ],
      "id": "c50ae0f2-a39f-4378-8ea3-f2a6a0d457bf",
      "name": "Code in JavaScript"
    }
  ],
  "connections": {
    "cancelAppointment": {
      "ai_tool": [
        [
          {
            "node": "AI Agent1",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "rescheduleAppointment": {
      "ai_tool": [
        [
          {
            "node": "AI Agent1",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "bookAppointment": {
      "ai_tool": [
        [
          {
            "node": "AI Agent1",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent1": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook1": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "getAvailability": {
      "ai_tool": [
        [
          {
            "node": "AI Agent1",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "getAppointment": {
      "ai_tool": [
        [
          {
            "node": "AI Agent1",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Respond to Webhook": {
      "main": [
        []
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent1",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "AI Agent1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "timezone": "Asia/Kolkata",
    "saveExecutionProgress": true,
    "callerPolicy": "workflowsFromSameOwner",
    "availableInMCP": false
  },
  "staticData": null,
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "versionId": "5541acbf-e935-40bd-afe2-3c68f9026c63",
  "triggerCount": 1,
  "shared": [
    {
      "updatedAt": "2025-10-27T18:25:39.013Z",
      "createdAt": "2025-10-27T18:25:39.013Z",
      "role": "workflow:owner",
      "workflowId": "eQO1bX8fadDwNvMu",
      "projectId": "U9gNtcfNPVWYu387"
    }
  ],
  "tags": []
}