{
  "name": "AI Customer Service Automation - Portfolio",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "Freshchat-agent",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        -768,
        768
      ],
      "id": "cf563fc0-d544-47e8-a9ed-625f5a0ad779",
      "name": "Webhook"
    },
    {
      "parameters": {
        "jsCode": "const items = $input.all();\n\n// --------------------------------------------------\n// KNOWN AUTOMATION / BOT ACTOR IDs\n// --------------------------------------------------\n// \u0647\u0630\u0647 IDs \u0644\u0628\u0648\u062a\u0627\u062a / \u0631\u0633\u0627\u0626\u0644 \u0622\u0644\u064a\u0629 \u0645\u0639\u0631\u0648\u0641\u0629 \u0639\u0646\u062f\u0646\u0627.\n// \u0645\u0645\u0646\u0648\u0639 \u0623\u064a \u0648\u0627\u062d\u062f \u0645\u0646\u0647\u0645 \u064a\u0648\u0642\u0641 \u0627\u0644\u0640 AI.\nconst AUTOMATION_ACTOR_IDS = [\n  'AUTOMATION_ACTOR_ID_1',\n  'AUTOMATION_ACTOR_ID_2',\n];\n\nreturn items.map((item) => {\n  const body = item.json.body ?? item.json;\n\n  const action = body.action ?? '';\n  const actorType = body.actor?.actor_type ?? '';\n  const actorId = body.actor?.actor_id ?? '';\n\n  let eventType = 'ignore';\n  let conversation = null;\n  let message = null;\n  let user = null;\n\n  // --------------------------------------------------\n  // 1) MESSAGE CREATED\n  // --------------------------------------------------\n  if (action === 'message_create') {\n    message = body.data?.message ?? {};\n\n    const messageActorId =\n      message?.actor_id ??\n      actorId ??\n      '';\n\n    const orgActorId =\n      message?.org_actor_id ??\n      null;\n\n    // -----------------------------\n    // Customer message\n    // -----------------------------\n    if (actorType === 'user') {\n      eventType = 'customer_message';\n\n    // -----------------------------\n    // Agent / Bot / AI message\n    // -----------------------------\n    } else if (actorType === 'agent') {\n\n      const isKnownAutomation =\n        AUTOMATION_ACTOR_IDS.includes(messageActorId);\n\n      // \u0627\u0644\u0645\u0648\u0638\u0641 \u0627\u0644\u0628\u0634\u0631\u064a \u0627\u0644\u062d\u0642\u064a\u0642\u064a \u064a\u0638\u0647\u0631 \u0645\u0639\u0647 org_actor_id\n      const isHumanAgent =\n        Boolean(orgActorId) &&\n        !isKnownAutomation;\n\n      if (isKnownAutomation) {\n        // \u0628\u0648\u062a Freshchat / Freshdesk \u0623\u0648 AI/n8n\n        eventType = 'automated_agent_message';\n\n      } else if (isHumanAgent) {\n        // \u0645\u0648\u0638\u0641 \u0628\u0634\u0631\u064a \u062d\u0642\u064a\u0642\u064a\n        eventType = 'human_agent_message';\n\n      } else {\n        // Agent \u063a\u064a\u0631 \u0645\u0639\u0631\u0648\u0641 \u0648\u0645\u0627 \u0639\u0646\u062f\u0647 org_actor_id.\n        // \u0646\u0639\u0627\u0645\u0644\u0647 \u0643\u0631\u0633\u0627\u0644\u0629 \u0622\u0644\u064a\u0629 \u062d\u062a\u0649 \u0644\u0627 \u0646\u0648\u0642\u0641 \u0627\u0644\u0640 AI \u0628\u0627\u0644\u063a\u0644\u0637\n        // \u0625\u0630\u0627 \u0638\u0647\u0631 \u0628\u0648\u062a \u062c\u062f\u064a\u062f \u0645\u0633\u062a\u0642\u0628\u0644\u064b\u0627.\n        eventType = 'automated_agent_message';\n      }\n\n    } else {\n      eventType = 'unknown_message';\n    }\n\n  // --------------------------------------------------\n  // 2) ASSIGN TO ME / CONVERSATION ASSIGNMENT\n  // --------------------------------------------------\n  } else if (action === 'conversation_assignment') {\n    conversation =\n      body.data?.assignment?.conversation ??\n      {};\n\n    const assignorId =\n      body.data?.assignment?.assignor_id ??\n      actorId ??\n      '';\n\n    // \u0625\u0630\u0627 assignment \u062c\u0627\u0621 \u0645\u0646 automation \u0645\u0639\u0631\u0648\u0641 \u0644\u0627 \u0646\u0648\u0642\u0641 AI.\n    // \u063a\u064a\u0631 \u0630\u0644\u0643 \u0646\u0639\u062a\u0628\u0631\u0647 \u062a\u062f\u062e\u0644 \u0645\u0648\u0638\u0641 \u0628\u0634\u0631\u064a.\n    if (AUTOMATION_ACTOR_IDS.includes(assignorId)) {\n      eventType = 'automated_assignment';\n    } else {\n      eventType = 'agent_assignment';\n    }\n\n  // --------------------------------------------------\n  // 3) RESOLVE\n  // --------------------------------------------------\n  } else if (action === 'conversation_resolution') {\n    conversation =\n      body.data?.resolve?.conversation ??\n      {};\n\n    user =\n      body.data?.resolve?.user ??\n      {};\n\n    eventType = 'conversation_resolved';\n\n  // --------------------------------------------------\n  // 4) REOPEN\n  // --------------------------------------------------\n  } else if (action === 'conversation_reopen') {\n    conversation =\n      body.data?.reopen?.conversation ??\n      {};\n\n    const reopenerId =\n      body.data?.reopen?.reopener_id ??\n      actorId ??\n      '';\n\n    if (actorType === 'user') {\n      eventType = 'customer_reopen';\n\n    } else if (actorType === 'agent') {\n\n      if (AUTOMATION_ACTOR_IDS.includes(reopenerId)) {\n        eventType = 'automated_reopen';\n      } else {\n        eventType = 'agent_reopen';\n      }\n\n    } else {\n      eventType = 'unknown_reopen';\n    }\n  }\n\n  // --------------------------------------------------\n  // Conversation ID\n  // --------------------------------------------------\n  const conversationId =\n    message?.conversation_id ??\n    conversation?.conversation_id ??\n    null;\n\n  // --------------------------------------------------\n  // Message Parts\n  // --------------------------------------------------\n  const messageParts =\n    message?.message_parts ??\n    [];\n\n  const messageText =\n    messageParts\n      .map((part) => part.text?.content)\n      .filter(Boolean)\n      .join('\\n') || null;\n\n  // --------------------------------------------------\n  // Images\n  // --------------------------------------------------\n  const imageUrls =\n    messageParts\n      .map((part) => part.image?.url)\n      .filter(Boolean);\n\n  // --------------------------------------------------\n  // AI ACTION\n  // --------------------------------------------------\n  let aiAction = 'ignore';\n\n  // \u0631\u0633\u0627\u0644\u0629 \u0627\u0644\u0639\u0645\u064a\u0644:\n  // \u0627\u0641\u062d\u0635 \u0647\u0644 AI \u0634\u063a\u0627\u0644 \u0623\u0648 \u0645\u0648\u0642\u0648\u0641\n  if (eventType === 'customer_message') {\n    aiAction = 'check_if_ai_active';\n  }\n\n  // \u0641\u0642\u0637 \u062a\u062f\u062e\u0644 \u0628\u0634\u0631\u064a \u062d\u0642\u064a\u0642\u064a \u064a\u0648\u0642\u0641 AI\n  if (\n    eventType === 'human_agent_message' ||\n    eventType === 'agent_assignment' ||\n    eventType === 'agent_reopen'\n  ) {\n    aiAction = 'pause_ai';\n  }\n\n  // Resolve \u064a\u0631\u062c\u0639 AI \u0644\u0644\u0639\u0645\u0644\n  if (\n    eventType === 'conversation_resolved' ||\n    eventType === 'customer_reopen'\n  ) {\n    aiAction = 'activate_ai';\n  }\n\n  // \u0647\u0630\u0647 \u0627\u0644\u062d\u0627\u0644\u0627\u062a \u0643\u0644\u0647\u0627 \u062a\u0628\u0642\u0649 ignore:\n  //\n  // automated_agent_message\n  // automated_assignment\n  // automated_reopen\n  //\n  // \u064a\u0639\u0646\u064a \u0627\u0644\u0628\u0648\u062a\u0627\u062a \u0648\u0631\u062f\u0648\u062f AI/n8n\n  // \u0645\u0645\u0646\u0648\u0639 \u062a\u063a\u064a\u0631 \u062d\u0627\u0644\u0629 \u0627\u0644\u0640 AI.\n\n  // --------------------------------------------------\n  // OUTPUT\n  // --------------------------------------------------\n  return {\n    json: {\n      request_id: body.request_id ?? null,\n      action,\n      action_time: body.action_time ?? null,\n\n      event_type: eventType,\n      ai_action: aiAction,\n\n      actor_type: actorType,\n      actor_id: actorId,\n\n      // \u0645\u0647\u0645 \u0644\u0644\u062a\u0634\u062e\u064a\u0635 \u0648\u0645\u0639\u0631\u0641\u0629 \u0627\u0644\u0628\u0634\u0631\u064a \u0645\u0646 \u0627\u0644\u0622\u0644\u064a\n      org_actor_id:\n        message?.org_actor_id ??\n        conversation?.assigned_org_agent_id ??\n        null,\n\n      conversation_id: conversationId,\n\n      conversation_status:\n        conversation?.status ??\n        null,\n\n      conversation_internal_id:\n        conversation?.conversation_internal_id ??\n        message?.freshchat_conversation_id ??\n        null,\n\n      user_id:\n        message?.user_id ??\n        conversation?.user_id ??\n        user?.id ??\n        null,\n\n      message_id:\n        message?.id ??\n        null,\n\n      message_type:\n        message?.message_type ??\n        null,\n\n      message_text: messageText,\n      message_parts: messageParts,\n\n      image_urls: imageUrls,\n      image_count: imageUrls.length,\n      has_images: imageUrls.length > 0,\n\n      channel_id:\n        message?.channel_id ??\n        conversation?.channel_id ??\n        null,\n\n      assigned_agent_id:\n        conversation?.assigned_agent_id ??\n        body.data?.assignment?.to_agent_id ??\n        null,\n\n      customer_phone:\n        user?.phone ??\n        null,\n\n      customer_name:\n        user?.first_name ??\n        null,\n\n      original_event: body,\n    },\n  };\n});"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -528,
        768
      ],
      "id": "45effbd4-f2c2-42bf-af7e-ed734b023857",
      "name": "Normalize Freshchat Event"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "f786292c-5b88-45bf-a56e-ad057bf244d0",
                    "leftValue": "={{ $json.ai_action }}",
                    "rightValue": "pause_ai",
                    "operator": {
                      "type": "string",
                      "operation": "regex"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Pause AI"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "83b59d66-c455-4619-9d51-d269d22ebde3",
                    "leftValue": "={{ $json.ai_action }}",
                    "rightValue": "activate_ai",
                    "operator": {
                      "type": "string",
                      "operation": "regex"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Activate AI"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.ai_action }}",
                    "rightValue": "check_if_ai_active",
                    "operator": {
                      "type": "string",
                      "operation": "regex"
                    },
                    "id": "66c61d1d-44fb-4cf9-8065-99f42496af12"
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Customer Message"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.4,
      "position": [
        -720,
        992
      ],
      "id": "a19651e3-d284-4ccd-80fe-c6d7fdb87c77",
      "name": "Route Freshchat Event"
    },
    {
      "parameters": {
        "operation": "appendOrUpdate",
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "list",
          "cachedResultName": "Customer Service AI System",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Conversation States",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit#gid=YOUR_SHEET_GID"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "conversation_id": "={{ $json.conversation_id }}",
            "conversation_internal_id": "={{ String($json.conversation_internal_id) }}",
            "user_id": "={{ $json.user_id }}",
            "ai_status": "paused",
            "last_event": "={{ $json.event_type }}",
            "updated_at": "={{ DateTime.fromISO($json.action_time).setZone('Asia/Riyadh').toFormat('yyyy-MM-dd HH:mm:ss') }}"
          },
          "matchingColumns": [
            "conversation_id"
          ],
          "schema": [
            {
              "id": "conversation_id",
              "displayName": "conversation_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "conversation_internal_id",
              "displayName": "conversation_internal_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "ai_status",
              "displayName": "ai_status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "last_event",
              "displayName": "last_event",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "updated_at",
              "displayName": "updated_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        672,
        992
      ],
      "id": "2cae8d75-4594-4a02-9f88-768adb49d9ea",
      "name": "Save Paused State",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "appendOrUpdate",
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "list",
          "cachedResultName": "Customer Service AI System",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Conversation States",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit#gid=YOUR_SHEET_GID"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "conversation_id": "={{ $json.conversation_id }}",
            "conversation_internal_id": "={{ String($json.conversation_internal_id) }}",
            "user_id": "={{ $json.user_id }}",
            "ai_status": "active",
            "last_event": "={{ $json.event_type }}",
            "updated_at": "={{ DateTime.fromISO($json.action_time).setZone('Asia/Riyadh').toFormat('yyyy-MM-dd HH:mm:ss') }}"
          },
          "matchingColumns": [
            "conversation_id"
          ],
          "schema": [
            {
              "id": "conversation_id",
              "displayName": "conversation_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "conversation_internal_id",
              "displayName": "conversation_internal_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "ai_status",
              "displayName": "ai_status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "last_event",
              "displayName": "last_event",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "updated_at",
              "displayName": "updated_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {
          "cellFormat": "RAW"
        }
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        960,
        992
      ],
      "id": "fefa7ebc-970e-4a68-a013-849e6f9617a3",
      "name": "Save Active State",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "list",
          "cachedResultName": "Customer Service AI System",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Conversation States",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit#gid=YOUR_SHEET_GID"
        },
        "filtersUI": {
          "values": [
            {
              "lookupColumn": "conversation_id",
              "lookupValue": "={{ $json.conversation_id }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        -448,
        1040
      ],
      "id": "c477de46-b18a-4d32-bb24-1d2f2339c38c",
      "name": "Get Conversation State",
      "alwaysOutputData": true,
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "9f2604bd-7463-4d7b-a97a-f51626dabf0b",
              "leftValue": "={{ $json.ai_status ?? 'active' }}",
              "rightValue": "active",
              "operator": {
                "type": "string",
                "operation": "equals",
                "name": "filter.operator.equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -224,
        1040
      ],
      "id": "a3f51ff9-4ec6-4fec-8001-6a51028f1dd5",
      "name": "Is AI Active?"
    },
    {
      "parameters": {
        "url": "=https://YOUR_FRESHCHAT_DOMAIN.freshchat.com/v2/users/{{ $('Normalize Freshchat Event').item.json.user_id }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        -16,
        1024
      ],
      "id": "dcbd77b6-11ce-41b7-9e56-5f8c6034c4fa",
      "name": "Get Freshchat Customer",
      "credentials": {
        "httpBasicAuth": {
          "name": "<your credential>"
        },
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "62dabe01-07b4-49ba-ab38-ddc12fbd36d4",
              "name": "customer_phone",
              "value": "={{ $json.phone }}",
              "type": "string"
            },
            {
              "id": "be61252e-dec9-4ae5-b0af-d3b8515e16b8",
              "name": "customer_message",
              "value": "={{ $('Normalize Freshchat Event').item.json.message_text }}",
              "type": "string"
            },
            {
              "id": "95bfc432-4333-4a60-9853-01e5196a7a73",
              "name": "conversation_id",
              "value": "={{ $('Normalize Freshchat Event').item.json.conversation_id }}",
              "type": "string"
            },
            {
              "id": "611e5382-ef32-49ae-a334-d320eb594a1a",
              "name": "conversation_internal_id",
              "value": "={{ String($('Normalize Freshchat Event').item.json.conversation_internal_id) }}",
              "type": "string"
            },
            {
              "id": "91b2e54d-080a-4306-a7b3-40e98cce32c8",
              "name": "user_id",
              "value": "={{ $('Normalize Freshchat Event').item.json.user_id }}",
              "type": "string"
            },
            {
              "id": "93e1de4b-9810-4827-aa24-b4d7616582f2",
              "name": "image_urls",
              "value": "={{ $('Normalize Freshchat Event').item.json.image_urls ?? [] }}",
              "type": "array"
            },
            {
              "id": "c7561f8c-9b43-44d0-ba49-06ab1270abf6",
              "name": "message_id",
              "value": "={{ $('Normalize Freshchat Event').item.json.message_id }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        208,
        1024
      ],
      "id": "8238386a-73ca-48b8-9658-7f0656edf107",
      "name": "Build Customer Context"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "0156eebf-91dc-4026-8213-7d21280b6f47",
              "leftValue": "={{ Array.isArray($json.image_urls) && $json.image_urls.length > 0 }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -720,
        1264
      ],
      "id": "0d43318e-42f9-468b-9774-0f32d459ac62",
      "name": "Has Images?"
    },
    {
      "parameters": {
        "amount": 6
      },
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        -224,
        1248
      ],
      "id": "ca4c4810-64ba-4547-afe3-2990c933d24f",
      "name": "Wait for More Images"
    },
    {
      "parameters": {
        "jsCode": "const rows = $input.all().map(item => item.json);\n\nif (rows.length === 0) {\n  return [];\n}\n\n// \u0627\u0644\u0631\u0633\u0627\u0644\u0629 \u0627\u0644\u062a\u064a \u0634\u063a\u0651\u0644\u062a \u0647\u0630\u0627 \u0627\u0644\u0640 Execution\nconst currentMessageId = String(\n  $('Build Customer Context').first().json.message_id ?? ''\n);\n\n// --------------------------------------------------\n// \u062a\u062d\u0648\u064a\u0644 \u0648\u0642\u062a Supabase \u0625\u0644\u0649 timestamp\n// received_at \u0645\u062b\u0627\u0644:\n// 2026-08-09T11:02:45.830+00:00\n// --------------------------------------------------\nfunction parseTime(value) {\n  if (!value) return null;\n\n  const time = Date.parse(String(value));\n  return Number.isFinite(time) ? time : null;\n}\n\n// --------------------------------------------------\n// \u062a\u062d\u062f\u064a\u062f \u0623\u062d\u062f\u062b \u0635\u0648\u0631\u0629 \u062d\u0633\u0628 received_at\n// \u0648\u0625\u0630\u0627 \u062a\u0633\u0627\u0648\u0649 \u0627\u0644\u0648\u0642\u062a \u0646\u0633\u062a\u062e\u062f\u0645 id\n// --------------------------------------------------\nconst latestRow = rows.reduce((latest, row) => {\n  const latestTime = parseTime(latest.received_at);\n  const rowTime = parseTime(row.received_at);\n\n  if (latestTime === null && rowTime !== null) {\n    return row;\n  }\n\n  if (latestTime !== null && rowTime === null) {\n    return latest;\n  }\n\n  if (latestTime === null && rowTime === null) {\n    return Number(row.id) > Number(latest.id)\n      ? row\n      : latest;\n  }\n\n  if (rowTime > latestTime) {\n    return row;\n  }\n\n  if (\n    rowTime === latestTime &&\n    Number(row.id) > Number(latest.id)\n  ) {\n    return row;\n  }\n\n  return latest;\n});\n\n// \u0641\u0642\u0637 Execution \u0627\u0644\u062e\u0627\u0635 \u0628\u0623\u062d\u062f\u062b \u0635\u0648\u0631\u0629 \u064a\u0643\u0645\u0644\nif (String(latestRow.message_id) !== currentMessageId) {\n  return [];\n}\n\n// --------------------------------------------------\n// \u0646\u0623\u062e\u0630 \u0641\u0642\u0637 \u0627\u0644\u0635\u0648\u0631 \u0627\u0644\u0642\u0631\u064a\u0628\u0629 \u0645\u0646 \u0623\u062d\u062f\u062b \u0635\u0648\u0631\u0629\n// \u062d\u062a\u0649 \u0627\u0644\u0635\u0648\u0631 \u0627\u0644\u0642\u062f\u064a\u0645\u0629 \u063a\u064a\u0631 \u0627\u0644\u0645\u0639\u0627\u0644\u062c\u0629 \u0644\u0627 \u062a\u062f\u062e\u0644 \u0641\u064a Batch \u062c\u062f\u064a\u062f\n// --------------------------------------------------\nconst latestTime = parseTime(latestRow.received_at);\n\nconst BATCH_WINDOW_MS = 60 * 1000;\n\nconst batchRows = rows.filter(row => {\n  const rowTime = parseTime(row.received_at);\n\n  if (latestTime === null || rowTime === null) {\n    return String(row.message_id) === String(latestRow.message_id);\n  }\n\n  return (\n    latestTime - rowTime >= 0 &&\n    latestTime - rowTime <= BATCH_WINDOW_MS\n  );\n});\n\n// --------------------------------------------------\n// \u062a\u0631\u062a\u064a\u0628 \u0635\u0641\u0648\u0641 \u0627\u0644\u062f\u0641\u0639\u0629 \u0645\u0646 \u0627\u0644\u0623\u0642\u062f\u0645 \u0625\u0644\u0649 \u0627\u0644\u0623\u062d\u062f\u062b\n// \u062d\u062a\u0649 \u0646\u062c\u0645\u0639 \u0627\u0644\u0646\u0635\u0648\u0635 \u0628\u0627\u0644\u062a\u0631\u062a\u064a\u0628 \u0627\u0644\u0635\u062d\u064a\u062d\n// --------------------------------------------------\nconst sortedBatchRows = [...batchRows].sort((a, b) => {\n  const timeA = parseTime(a.received_at);\n  const timeB = parseTime(b.received_at);\n\n  if (timeA === null && timeB === null) {\n    return Number(a.id) - Number(b.id);\n  }\n\n  if (timeA === null) return -1;\n  if (timeB === null) return 1;\n\n  if (timeA !== timeB) {\n    return timeA - timeB;\n  }\n\n  return Number(a.id) - Number(b.id);\n});\n\n// --------------------------------------------------\n// \u062a\u062c\u0645\u064a\u0639 \u0631\u0648\u0627\u0628\u0637 \u0627\u0644\u0635\u0648\u0631\n// --------------------------------------------------\nconst imageUrls = [];\n\nfor (const row of sortedBatchRows) {\n  let urls = row.image_urls;\n\n  if (typeof urls === 'string') {\n    try {\n      urls = JSON.parse(urls);\n    } catch {\n      urls = urls ? [urls] : [];\n    }\n  }\n\n  if (Array.isArray(urls)) {\n    imageUrls.push(...urls);\n  }\n}\n\n// --------------------------------------------------\n// \u062a\u062c\u0645\u064a\u0639 \u0646\u0635\u0648\u0635 \u0646\u0641\u0633 \u0627\u0644\u0640 Batch\n// --------------------------------------------------\nconst textParts = sortedBatchRows\n  .map(row => String(row.message_text ?? '').trim())\n  .filter(text => text.length > 0);\n\nconst batchMessageText = textParts.join('\\n');\n\nreturn [\n  {\n    json: {\n      conversation_id: latestRow.conversation_id,\n      conversation_internal_id: latestRow.conversation_internal_id,\n      user_id: latestRow.user_id,\n      customer_phone: latestRow.customer_phone,\n\n      image_urls: [...new Set(imageUrls)],\n\n      batch_message_text: batchMessageText,\n\n      buffered_message_ids: sortedBatchRows.map(row => row.message_id),\n\n      // \u0628\u062f\u0644 row_number \u062a\u0628\u0639 Google Sheets\n      buffer_ids: sortedBatchRows.map(row => row.id)\n    }\n  }\n];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        224,
        1248
      ],
      "id": "20bded24-0a46-4432-b62b-3fb49ebb3e26",
      "name": "Keep Latest Image Batch"
    },
    {
      "parameters": {
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "list",
          "cachedResultName": "Customer Service AI System",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit"
        },
        "sheetName": {
          "__rl": true,
          "value": 128263397,
          "mode": "list",
          "cachedResultName": "Issue Drafts",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit#gid=YOUR_SHEET_GID"
        },
        "filtersUI": {
          "values": [
            {
              "lookupColumn": "conversation_id",
              "lookupValue": "={{ $json.conversation_id }}"
            },
            {
              "lookupColumn": "status",
              "lookupValue": "collecting"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        448,
        1248
      ],
      "id": "af7d7a24-e8c0-483b-a33b-1c9011b17dcc",
      "name": "Get Collecting Issue",
      "alwaysOutputData": true,
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "fe7eac9b-59dc-4967-98a3-341d759a25fc",
              "leftValue": "={{ $json.row_number !== undefined }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -720,
        1472
      ],
      "id": "173ed7da-71a6-4fd8-a642-e58c1291ce08",
      "name": "Collecting Issue Exists?"
    },
    {
      "parameters": {
        "jsCode": "const draft = $input.first().json;\nconst newBatch = $('Keep Latest Image Batch').first().json;\n\nfunction toArray(value) {\n  if (Array.isArray(value)) return value;\n  if (!value) return [];\n\n  if (typeof value === 'string') {\n    try {\n      const parsed = JSON.parse(value);\n      return Array.isArray(parsed) ? parsed : [parsed];\n    } catch {\n      return [value];\n    }\n  }\n\n  return [value];\n}\n\nconst oldImages = toArray(draft.image_urls);\nconst newImages = toArray(newBatch.image_urls);\n\nconst mergedImages = [...new Set([\n  ...oldImages,\n  ...newImages\n])];\n\nreturn [{\n  json: {\n    row_number: draft.row_number,\n    issue_id: draft.issue_id,\n    image_urls: JSON.stringify(mergedImages)\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -448,
        1456
      ],
      "id": "08be4247-3467-4fc2-aeb9-5338b0028a6e",
      "name": "Merge New Images Into Draft"
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "list",
          "cachedResultName": "Customer Service AI System",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit"
        },
        "sheetName": {
          "__rl": true,
          "value": 128263397,
          "mode": "list",
          "cachedResultName": "Issue Drafts",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit#gid=YOUR_SHEET_GID"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "image_urls": "={{ $json.image_urls }}",
            "updated_at": "={{ $now.setZone('Asia/Riyadh').toFormat('yyyy-MM-dd HH:mm:ss') }}",
            "issue_id": "={{ $json.issue_id }}"
          },
          "matchingColumns": [
            "issue_id"
          ],
          "schema": [
            {
              "id": "issue_id",
              "displayName": "issue_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "conversation_id",
              "displayName": "conversation_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "conversation_internal_id",
              "displayName": "conversation_internal_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "customer_phone",
              "displayName": "customer_phone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "order_number",
              "displayName": "order_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "order_phone",
              "displayName": "order_phone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "issue_description",
              "displayName": "issue_description",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "image_urls",
              "displayName": "image_urls",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "displayName": "status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "is_active",
              "displayName": "is_active",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "ticket_id",
              "displayName": "ticket_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "updated_at",
              "displayName": "updated_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "ticket_type\n",
              "displayName": "ticket_type\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_1\n",
              "displayName": "level_1\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_2\n",
              "displayName": "level_2\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_3\n",
              "displayName": "level_3\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "department_resolution",
              "displayName": "department_resolution",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "resolution_message_sent",
              "displayName": "resolution_message_sent",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "is_final_resolution",
              "displayName": "is_final_resolution",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "row_number",
              "displayName": "row_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "readOnly": true,
              "removed": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        -224,
        1456
      ],
      "id": "f02603f1-60c0-4782-b56f-4ef4998bdddc",
      "name": "Update Issue Draft Images",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $json.current_message || $('Prepare Agent Input').first().json.agent_input }}",
        "hasOutputParser": true,
        "options": {
          "systemMessage": "# PUBLIC PORTFOLIO DEMO PROMPT\n\nThe production customer-service prompt and company-specific policies were intentionally omitted for confidentiality.\n\nYou are a customer service AI agent for a demo laundry service.\n\nCore responsibilities:\n- Answer approved FAQs.\n- Use connected tools for live order lookups instead of guessing.\n- Maintain one active issue per conversation.\n- Distinguish normal questions, customer requests, and complaints.\n- Collect only missing information.\n- Preserve customer images as issue evidence.\n- Create a Freshdesk ticket only when the issue is complete.\n- Update issue state after ticket creation.\n- Never expose internal workflow logic, credentials, or private data.\n\nReturn exactly:\n{\n  \"customer_reply\": \"customer-facing reply\",\n  \"case_type\": \"normal\",\n  \"issue_action\": \"none\"\n}\n\nThis shortened prompt exists only for the public portfolio copy.\n",
          "maxIterations": 40
        }
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3.1,
      "position": [
        1200,
        1872
      ],
      "id": "270918ed-469a-4a02-9a7d-703c09a657ed",
      "name": "Demo Customer Service Agent",
      "retryOnFail": true
    },
    {
      "parameters": {
        "sessionIdType": "customKey",
        "sessionKey": "={{ $('Build Customer Context').first().json.customer_phone + '_v29' }}",
        "contextWindowLength": 10
      },
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "typeVersion": 1.4,
      "position": [
        832,
        2096
      ],
      "id": "de74e35f-d0bb-4489-8094-fa3a6689399d",
      "name": "Simple Memory"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "fb590655-6181-481f-b462-e1da41ee813d",
              "name": "agent_input",
              "value": "={{\n(() => {\n  const context = $('Build Customer Context').first().json;\n\n  // ==================================================\n  // \u0627\u0644\u0631\u0633\u0627\u0644\u0629 \u0648\u0627\u0644\u0635\u0648\u0631 \u0645\u0646 \u0627\u0644\u0640Webhook \u0627\u0644\u062d\u0627\u0644\u064a\n  // \u062a\u0633\u062a\u062e\u062f\u0645 \u0643\u0640 fallback \u0644\u0644\u0631\u0633\u0627\u0626\u0644 \u0627\u0644\u0639\u0627\u062f\u064a\u0629\n  // ==================================================\n\n  const currentMessage = String(\n    context.customer_message || ''\n  ).trim();\n\n  const currentImages = Array.isArray(context.image_urls)\n    ? context.image_urls\n    : [];\n\n  // ==================================================\n  // \u0646\u062d\u0627\u0648\u0644 \u0623\u062e\u0630 \u0627\u0644\u0640Batch \u0627\u0644\u0643\u0627\u0645\u0644 \u0625\u0630\u0627 \u0645\u0631 \u0627\u0644\u062a\u0646\u0641\u064a\u0630 \u0628\u0645\u0633\u0627\u0631 \u0627\u0644\u0635\u0648\u0631\n  // ==================================================\n\n  let batchMessage = '';\n  let batchImages = [];\n\n  try {\n    const batch = $('Keep Latest Image Batch').first().json;\n\n    batchMessage = String(\n      batch.batch_message_text || ''\n    ).trim();\n\n    batchImages = Array.isArray(batch.image_urls)\n      ? batch.image_urls\n      : [];\n  } catch (e) {\n    // \u0627\u0644\u0631\u0633\u0627\u0644\u0629 \u0644\u0645 \u062a\u0645\u0631 \u0628\u0645\u0633\u0627\u0631 \u0627\u0644\u0635\u0648\u0631\n  }\n\n  // \u0625\u0630\u0627 \u0643\u0627\u0646 \u0639\u0646\u062f\u0646\u0627 Batch \u0635\u0648\u0631 \u0646\u0633\u062a\u062e\u062f\u0645 \u0628\u064a\u0627\u0646\u0627\u062a\u0647.\n  // \u0648\u0625\u0630\u0627 \u0643\u0627\u0646\u062a \u0631\u0633\u0627\u0644\u0629 \u0639\u0627\u062f\u064a\u0629 \u0646\u0633\u062a\u062e\u062f\u0645 Build Customer Context.\n  const message = batchMessage || currentMessage;\n\n  const images = batchImages.length > 0\n    ? batchImages\n    : currentImages;\n\n  // ==================================================\n  // \u0647\u0644 \u064a\u0648\u062c\u062f Issue Draft \u062d\u0627\u0644\u064a \u0628\u062d\u0627\u0644\u0629 collecting\u061f\n  // ==================================================\n\n  let hasCollectingIssue = false;\n\n  try {\n    const draft = $('Get Collecting Issue').first().json;\n\n    hasCollectingIssue =\n      draft &&\n      draft.row_number !== undefined;\n  } catch (e) {\n    hasCollectingIssue = false;\n  }\n\n  // ==================================================\n  // \u064a\u0648\u062c\u062f Issue Draft \u062d\u0642\u064a\u0642\u064a \u0645\u0641\u062a\u0648\u062d\n  // ==================================================\n\n  if (hasCollectingIssue) {\n\n    if (message && images.length) {\n      return (\n        message +\n        '\\n\\n[\u0627\u0644\u0639\u0645\u064a\u0644 \u0623\u0631\u0633\u0644 \u0635\u0648\u0631\u0629 \u0623\u0648 \u0623\u0643\u062b\u0631\u060c \u0648\u062a\u0645\u062a \u0625\u0636\u0627\u0641\u0629 \u0627\u0644\u0635\u0648\u0631 \u0625\u0644\u0649 \u0645\u0633\u0648\u062f\u0629 \u0627\u0644\u0645\u0634\u0643\u0644\u0629 \u0627\u0644\u062d\u0627\u0644\u064a\u0629. \u0644\u0627 \u062a\u0637\u0644\u0628 \u0645\u0646\u0647 \u0625\u0639\u0627\u062f\u0629 \u0625\u0631\u0633\u0627\u0644\u0647\u0627\u060c \u0648\u062a\u0627\u0628\u0639 \u062c\u0645\u0639 \u0627\u0644\u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0627\u0644\u0646\u0627\u0642\u0635\u0629 \u0644\u0644\u0645\u0634\u0643\u0644\u0629.]'\n      );\n    }\n\n    if (message) {\n      return message;\n    }\n\n    if (images.length) {\n      return '[\u0627\u0644\u0639\u0645\u064a\u0644 \u0623\u0631\u0633\u0644 \u0635\u0648\u0631\u0629 \u0623\u0648 \u0623\u0643\u062b\u0631 \u0648\u062a\u0645\u062a \u0625\u0636\u0627\u0641\u062a\u0647\u0627 \u0625\u0644\u0649 \u0645\u0633\u0648\u062f\u0629 \u0627\u0644\u0645\u0634\u0643\u0644\u0629 \u0627\u0644\u062d\u0627\u0644\u064a\u0629. \u0644\u0627 \u062a\u0637\u0644\u0628 \u0645\u0646\u0647 \u0625\u0639\u0627\u062f\u0629 \u0625\u0631\u0633\u0627\u0644\u0647\u0627\u060c \u0648\u062a\u0627\u0628\u0639 \u062c\u0645\u0639 \u0627\u0644\u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0627\u0644\u0646\u0627\u0642\u0635\u0629 \u0644\u0644\u0645\u0634\u0643\u0644\u0629.]';\n    }\n  }\n\n  // ==================================================\n  // \u0644\u0627 \u064a\u0648\u062c\u062f Issue Draft\n  // ==================================================\n\n  if (message && images.length) {\n    return (\n      message +\n      '\\n\\n[\u0627\u0644\u0639\u0645\u064a\u0644 \u0623\u0631\u0633\u0644 \u0635\u0648\u0631\u0629 \u0623\u0648 \u0623\u0643\u062b\u0631 \u0645\u0639 \u0647\u0630\u0647 \u0627\u0644\u0631\u0633\u0627\u0644\u0629. \u0644\u0627 \u062a\u0641\u062a\u0631\u0636 \u0623\u0646 \u0627\u0644\u0635\u0648\u0631\u0629 \u0634\u0643\u0648\u0649 \u0623\u0648 \u0645\u0634\u0643\u0644\u0629 \u0645\u0646 \u062a\u0644\u0642\u0627\u0621 \u0646\u0641\u0633\u0647\u0627. \u0627\u0641\u0647\u0645 \u0627\u0644\u063a\u0631\u0636 \u0645\u0646 \u0643\u0644\u0627\u0645 \u0627\u0644\u0639\u0645\u064a\u0644 \u0648\u0633\u064a\u0627\u0642 \u0627\u0644\u0645\u062d\u0627\u062f\u062b\u0629. \u0644\u0627 \u062a\u0637\u0644\u0628 \u0645\u0646\u0647 \u0625\u0639\u0627\u062f\u0629 \u0625\u0631\u0633\u0627\u0644 \u0627\u0644\u0635\u0648\u0631\u0629 \u0627\u0644\u062d\u0627\u0644\u064a\u0629.]'\n    );\n  }\n\n  if (message) {\n    return message;\n  }\n\n  if (images.length) {\n    return '[\u0627\u0644\u0639\u0645\u064a\u0644 \u0623\u0631\u0633\u0644 \u0635\u0648\u0631\u0629 \u0623\u0648 \u0623\u0643\u062b\u0631 \u0628\u062f\u0648\u0646 \u0646\u0635. \u0644\u0627 \u062a\u0641\u062a\u0631\u0636 \u0623\u0646\u0647\u0627 \u0634\u0643\u0648\u0649 \u0623\u0648 \u0645\u0634\u0643\u0644\u0629. \u0625\u0630\u0627 \u0644\u0645 \u064a\u0643\u0646 \u0627\u0644\u063a\u0631\u0636 \u0648\u0627\u0636\u062d\u064b\u0627\u060c \u0627\u0633\u0623\u0644 \u0627\u0644\u0639\u0645\u064a\u0644 \u0628\u0627\u062e\u062a\u0635\u0627\u0631 \u0645\u0627\u0630\u0627 \u064a\u0631\u064a\u062f \u0628\u062e\u0635\u0648\u0635 \u0627\u0644\u0635\u0648\u0631\u0629\u060c \u0648\u0644\u0627 \u062a\u0637\u0644\u0628 \u0645\u0646\u0647 \u0625\u0639\u0627\u062f\u0629 \u0625\u0631\u0633\u0627\u0644 \u0627\u0644\u0635\u0648\u0631\u0629 \u0627\u0644\u062d\u0627\u0644\u064a\u0629.]';\n  }\n\n  return '\u0648\u0635\u0644\u062a \u0631\u0633\u0627\u0644\u0629 \u0645\u0646 \u0627\u0644\u0639\u0645\u064a\u0644 \u062f\u0648\u0646 \u0646\u0635 \u0623\u0648 \u0635\u0648\u0631 \u0642\u0627\u0628\u0644\u0629 \u0644\u0644\u0642\u0631\u0627\u0621\u0629.';\n})()\n}}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -448,
        1648
      ],
      "id": "f8cc9318-99a0-4755-9d2e-0354a0e901a3",
      "name": "Prepare Agent Input"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "2c4841d6-8225-4b30-bf87-c94198feaa02",
              "leftValue": "={{ $json.body.data.message.user_id }}",
              "rightValue": "YOUR_TEST_USER_ID",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -576,
        528
      ],
      "id": "2c134549-36fb-4e17-91a9-39d242204c29",
      "name": "If"
    },
    {
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"customer_reply\": {\n      \"type\": \"string\"\n    },\n    \"case_type\": {\n      \"type\": \"string\",\n      \"enum\": [\n        \"normal\",\n        \"bag_info\",\n        \"bag_image\",\n        \"sack_image\",\n        \"how_to_order\",\n        \"how_to_hang_bag\"\n      ]\n    },\n    \"issue_action\": {\n      \"type\": \"string\",\n      \"enum\": [\n        \"none\",\n        \"start_issue\",\n        \"await_context\"\n      ]\n    }\n  },\n  \"required\": [\n    \"customer_reply\",\n    \"case_type\",\n    \"issue_action\"\n  ],\n  \"additionalProperties\": false\n}",
        "autoFix": true
      },
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "typeVersion": 1.3,
      "position": [
        1856,
        2096
      ],
      "id": "2c912924-ae46-49d4-9b13-d80ea314d3d2",
      "name": "Structured Output Parser",
      "executeOnce": false,
      "retryOnFail": true
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://YOUR_FRESHCHAT_DOMAIN.freshchat.com/v2/conversations/{{ $('Normalize Freshchat Event').first().json.conversation_id }}/messages",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_API_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Accept",
              "value": "application/json"
            },
            {
              "name": "ASSUME-IDENTITY",
              "value": "false"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"message_parts\": [\n    {\n      \"text\": {\n        \"content\": {{ JSON.stringify($json.output.customer_reply) }}\n      }\n    }\n  ],\n  \"message_type\": \"normal\",\n  \"actor_type\": \"bot\"\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        1680,
        1872
      ],
      "id": "2b67c8bf-20e6-46a2-aa3c-daeb4fa2ab3a",
      "name": "Send Customer Reply"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "leftValue": "bag_info",
                    "rightValue": "={{ $('Demo Customer Service Agent').item.json.output.case_type }}",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "id": "d0bae682-a664-4b18-850d-6e01638af93b"
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Bag Info"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "ebe29642-52d7-453a-9de8-d2fab3edcec3",
                    "leftValue": "bag_image",
                    "rightValue": "={{ $('Demo Customer Service Agent').item.json.output.case_type }}",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Bag Image"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "d6f387b6-1335-4ae1-8d00-94d02a862099",
                    "leftValue": "sack_image",
                    "rightValue": "={{ $('Demo Customer Service Agent').item.json.output.case_type }}",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Sack Image"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "2f1c6f55-ee4e-4c8a-a808-7c4feff71edd",
                    "leftValue": "how_to_order",
                    "rightValue": "={{ $('Demo Customer Service Agent').item.json.output.case_type }}",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "How To Order"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "c2431f23-97ee-4afa-9150-17534f26a1e5",
                    "leftValue": "how_to_hang_bag",
                    "rightValue": "={{ $('Demo Customer Service Agent').item.json.output.case_type }}",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "How To Hang Bag"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 3
                },
                "conditions": [
                  {
                    "id": "20bb0368-a6c8-48cb-a28a-fb5c3b0f5b5b",
                    "leftValue": "normal",
                    "rightValue": "={{ $('Demo Customer Service Agent').item.json.output.case_type }}",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "Normal"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.4,
      "position": [
        2032,
        1808
      ],
      "id": "8336987d-f0e9-4723-a0a0-bfc2deaf9e53",
      "name": "Route Media Response"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://YOUR_FRESHCHAT_DOMAIN.freshchat.com/v2/conversations/{{ $('Normalize Freshchat Event').item.json.conversation_id }}/messages",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_API_TOKEN"
            },
            {
              "name": "Accept",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"message_parts\": [\n    {\n      \"image\": {\n        \"url\": \"https://drive.google.com/uc?export=view&id=YOUR_PUBLIC_ASSET_ID_1\"\n      }\n    },\n    {\n      \"image\": {\n        \"url\": \"https://drive.google.com/uc?export=view&id=YOUR_PUBLIC_ASSET_ID_2\"\n      }\n    }\n  ],\n  \"message_type\": \"normal\",\n  \"actor_type\": \"bot\"\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        2384,
        1872
      ],
      "id": "adbfb079-9a10-488d-ac3d-f9515d5e6d4e",
      "name": "Send Plastic Bag Image"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://YOUR_FRESHCHAT_DOMAIN.freshchat.com/v2/conversations/{{ $('Normalize Freshchat Event').item.json.conversation_id }}/messages",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_API_TOKEN"
            },
            {
              "name": "Accept",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"message_parts\": [\n    {\n      \"image\": {\n        \"url\": \"https://drive.google.com/uc?export=view&id=YOUR_PUBLIC_ASSET_ID_3\"\n      }\n    }\n  ],\n  \"message_type\": \"normal\",\n  \"actor_type\": \"bot\"\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        2384,
        1472
      ],
      "id": "4c8636d3-750c-41b9-affc-467b31b5c17a",
      "name": "Send Bag Info"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://YOUR_FRESHCHAT_DOMAIN.freshchat.com/v2/conversations/{{ $('Normalize Freshchat Event').item.json.conversation_id }}/messages",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_API_TOKEN"
            },
            {
              "name": "Accept",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"message_parts\": [\n    {\n      \"image\": {\n        \"url\": \"https://drive.google.com/uc?export=view&id=YOUR_PUBLIC_ASSET_ID_4\"\n      }\n    },\n    {\n      \"image\": {\n        \"url\": \"https://drive.google.com/uc?export=view&id=YOUR_PUBLIC_ASSET_ID_5\"\n      }\n    }\n  ],\n  \"message_type\": \"normal\",\n  \"actor_type\": \"bot\"\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        2384,
        1664
      ],
      "id": "89f84801-1a26-4e64-8859-2ec47a3e5fd3",
      "name": "Send Bag Image"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://YOUR_FRESHCHAT_DOMAIN.freshchat.com/v2/conversations/{{ $('Normalize Freshchat Event').item.json.conversation_id }}/messages",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_API_TOKEN"
            },
            {
              "name": "Accept",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"message_parts\": [\n    {\n      \"image\": {\n        \"url\": \"https://drive.google.com/uc?export=view&id=YOUR_PUBLIC_ASSET_ID_6\"\n      }\n    }\n  ],\n  \"message_type\": \"normal\",\n  \"actor_type\": \"bot\"\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        2384,
        2256
      ],
      "id": "c3a94da8-7921-4806-b27f-5b0e1145ca68",
      "name": "Send How To Hang Bag Image"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://YOUR_FRESHCHAT_DOMAIN.freshchat.com/v2/conversations/{{ $('Normalize Freshchat Event').item.json.conversation_id }}/messages",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_API_TOKEN"
            },
            {
              "name": "Accept",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"message_parts\": [\n    {\n      \"image\": {\n        \"url\": \"https://drive.google.com/uc?export=view&id=YOUR_PUBLIC_ASSET_ID_7\"\n      }\n    }\n  ],\n  \"message_type\": \"normal\",\n  \"actor_type\": \"bot\"\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        2384,
        2064
      ],
      "id": "38bedd09-dbe4-4159-9160-d4108531912f",
      "name": "Send How To Order Image"
    },
    {
      "parameters": {
        "toolDescription": "Creates one Freshdesk ticket for the current completed issue draft. Production field mappings and business rules are omitted from this public portfolio copy.",
        "method": "POST",
        "url": "https://YOUR_FRESHDESK_DOMAIN.freshdesk.com/api/v2/tickets",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({\n  subject: 'Demo Customer Support Request',\n  description: $('Get Current Issue Draft').first().json.issue_description || 'Demo issue description',\n  status: 2,\n  priority: 1,\n  custom_fields: {\n    cf_brief_description: $('Get Current Issue Draft').first().json.issue_description || ''\n  }\n}) }}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequestTool",
      "typeVersion": 4.4,
      "position": [
        960,
        2096
      ],
      "id": "2ae4a14f-2ed3-41ea-9ec9-f7b6124a0a0d",
      "name": "create_freshdesk_ticket",
      "credentials": {
        "httpBasicAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "toolDescription": "Retrieves the current order status from a protected internal order-status API using the confirmed order phone.",
        "method": "POST",
        "url": "https://YOUR_INTERNAL_API_DOMAIN/apis/whatsapp-bot/orderdetails",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "phone",
              "value": "={{\n(() => {\n  const currentPhone = String(\n    $('Build Customer Context').item.json.customer_phone || ''\n  )\n    .replace(/\\D/g, '')\n    .trim();\n\n  const lookupPhone = String(\n    $fromAI(\n      'status_lookup_phone',\n      'Return only the exact alternate phone number when the current order is confirmed to be associated with another phone. If the order uses the current conversation phone, return an empty string so the system uses the conversation phone automatically. If the current active collecting issue already has a confirmed alternate order phone and this status check is for that same issue, reuse that exact confirmed phone and do not ask the customer again. Include the country code. Never guess or invent a phone number.',\n      'string',\n      ''\n    ) || ''\n  )\n    .replace(/\\D/g, '')\n    .trim();\n\n  const phoneToUse = lookupPhone || currentPhone;\n\n  if (!phoneToUse) {\n    throw new Error(\n      'A valid phone number is required to retrieve the order status.'\n    );\n  }\n\n  return phoneToUse;\n})()\n}}"
            }
          ]
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "x-client-id ",
              "value": "6f592a62d7ccf8da6c42e82c511641ed"
            },
            {
              "name": "x-client-secret ",
              "value": "YOUR_CLIENT_SECRET"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequestTool",
      "typeVersion": 4.4,
      "position": [
        1088,
        2096
      ],
      "id": "3d07e3e5-e565-4f3c-a19b-a59524774a6a",
      "name": "Get Order Status"
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Reads the active issue state for the current conversation so the workflow avoids duplicate issues and tickets.",
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "list",
          "cachedResultName": "Customer Service AI System",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit"
        },
        "sheetName": {
          "__rl": true,
          "value": 128263397,
          "mode": "list",
          "cachedResultName": "Issue Drafts",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit#gid=YOUR_SHEET_GID"
        },
        "filtersUI": {
          "values": [
            {
              "lookupColumn": "conversation_id",
              "lookupValue": "={{ $('Build Customer Context').item.json.conversation_id }}"
            },
            {
              "lookupColumn": "is_active",
              "lookupValue": "={{true}}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheetsTool",
      "typeVersion": 4.7,
      "position": [
        1216,
        2096
      ],
      "id": "967113a6-40f1-4be8-b117-139e054b815d",
      "name": "Get Current Issue Draft",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Updates the current issue state after a successful operational step such as Freshdesk ticket creation.",
        "operation": "update",
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "list",
          "cachedResultName": "Customer Service AI System",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit"
        },
        "sheetName": {
          "__rl": true,
          "value": 128263397,
          "mode": "list",
          "cachedResultName": "Issue Drafts",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit#gid=YOUR_SHEET_GID"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "status": "pending",
            "updated_at": "={{ $now.setZone('Asia/Riyadh').toFormat('yyyy-MM-dd HH:mm:ss') }}",
            "ticket_id": "={{\n(() => {\n  const ticketId = Number(\n    $fromAI(\n      'update_freshdesk_ticket_id',\n      'Return only the exact numeric id returned by create_freshdesk_ticket for the Freshdesk ticket that was just created for this same issue. Never invent or modify the ticket id.',\n      'number',\n      0\n    )\n  );\n\n  if (!Number.isFinite(ticketId) || ticketId <= 0) {\n    throw new Error(\n      'A valid Freshdesk ticket ID is required before updating the Issue Draft.'\n    );\n  }\n\n  return ticketId;\n})()\n}}",
            "issue_id": "={{\n(() => {\n  const issueId = String(\n    $fromAI(\n      'update_issue_id',\n      'Return only the exact issue_id of the SAME current issue that was returned by Save Issue Draft or Get Current Issue Draft immediately before creating the Freshdesk ticket. Never invent or modify the issue_id.',\n      'string',\n      ''\n    ) || ''\n  ).trim();\n\n  if (!issueId || !issueId.startsWith('issue_')) {\n    throw new Error(\n      'A valid exact issue_id is required to update the Issue Draft.'\n    );\n  }\n\n  return issueId;\n})()\n}}",
            "is_active": "={{true}}"
          },
          "matchingColumns": [
            "issue_id"
          ],
          "schema": [
            {
              "id": "issue_id",
              "displayName": "issue_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "conversation_id",
              "displayName": "conversation_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "conversation_internal_id",
              "displayName": "conversation_internal_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "customer_phone",
              "displayName": "customer_phone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "order_number",
              "displayName": "order_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "order_phone",
              "displayName": "order_phone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "issue_description",
              "displayName": "issue_description",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "image_urls",
              "displayName": "image_urls",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "status",
              "displayName": "status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "is_active",
              "displayName": "is_active",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "ticket_id",
              "displayName": "ticket_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "updated_at",
              "displayName": "updated_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "ticket_type\n",
              "displayName": "ticket_type\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_1\n",
              "displayName": "level_1\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_2\n",
              "displayName": "level_2\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_3\n",
              "displayName": "level_3\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "department_resolution",
              "displayName": "department_resolution",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "resolution_message_sent",
              "displayName": "resolution_message_sent",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "is_final_resolution",
              "displayName": "is_final_resolution",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "row_number",
              "displayName": "row_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "readOnly": true,
              "removed": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheetsTool",
      "typeVersion": 4.7,
      "position": [
        1344,
        2096
      ],
      "id": "152e8533-a94f-45c9-ae17-7975ad98109c",
      "name": "Update Issue Draft",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Creates or updates the current collecting issue draft while preserving previously confirmed information.",
        "operation": "appendOrUpdate",
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "list",
          "cachedResultName": "Customer Service AI System",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit"
        },
        "sheetName": {
          "__rl": true,
          "value": 128263397,
          "mode": "list",
          "cachedResultName": "Issue Drafts",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit#gid=YOUR_SHEET_GID"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "issue_id": "={{\n(() => {\n\n  const issueState = String(\n    $fromAI(\n      'save_issue_id',\n      `MANDATORY ISSUE ID DECISION.\n\nUse ONLY the result returned by Get Current Issue Draft in the CURRENT customer turn.\n\nIf Get Current Issue Draft returned status = collecting:\nReturn ONLY the exact existing issue_id from that result.\nDo not modify it.\nDo not generate a new ID.\nDo not return NEW.\n\nIf Get Current Issue Draft returned status = pending:\nReturn exactly BLOCK.\n\nIf Get Current Issue Draft genuinely returned NO active issue:\nReturn exactly NEW.\n\nNever invent an issue_id.\nNever use conversation memory as the source of issue_id.`,\n      'string',\n      ''\n    ) || ''\n  ).trim();\n\n\n  // Existing pending issue must block writes\n  if (issueState === 'BLOCK') {\n    throw new Error(\n      'Active pending issue exists. Save Issue Draft is blocked.'\n    );\n  }\n\n\n  // Existing collecting issue \u2192 SAME ROW\n  if (issueState.startsWith('issue_')) {\n    return issueState;\n  }\n\n\n  // Only genuine \"no active issue\" may create a new ID\n  if (issueState === 'NEW') {\n\n    const conversationId = String(\n      $('Build Customer Context').first().json.conversation_id || ''\n    ).trim();\n\n    if (!conversationId) {\n      throw new Error(\n        'conversation_id is required to create a new issue_id.'\n      );\n    }\n\n    const executionId = String(\n      $execution.id || ''\n    ).trim();\n\n    if (!executionId) {\n      throw new Error(\n        'execution_id is required to create a new issue_id.'\n      );\n    }\n\n    return `issue_${conversationId}_${executionId}`;\n  }\n\n\n  throw new Error(\n    'Invalid save_issue_id decision. Expected exact existing issue_id, NEW, or BLOCK.'\n  );\n\n})()\n}}",
            "conversation_id": "={{ String($('Build Customer Context').first().json.conversation_id || '').trim() }}",
            "order_number": "={{\n(() => {\n  let currentDraft = null;\n\n  try {\n    currentDraft = $('Get Current Issue Draft').first().json;\n  } catch (e) {\n    currentDraft = null;\n  }\n\n  const existingOrderNumber = String(\n    currentDraft?.order_number || ''\n  ).trim();\n\n  // Preserve an already verified order number.\n  if (existingOrderNumber) {\n    return existingOrderNumber;\n  }\n\n  const verifiedOrderNumber = String(\n    $fromAI(\n      'order_number',\n      'Return only the exact currentOrderId returned by Demo Customer Metrics for the confirmed phone associated with this order. Use it only when the current issue is actually related to a specific order. Never use an order number from customer text as the verified source. Never guess or invent it. For non-order issues such as OTP/account creation, subscription payment issues, general Customer Service complaints, or Company Policy complaints that are not tied to a specific order, return an empty string.',\n      'string',\n      ''\n    ) || ''\n  ).trim();\n\n  return verifiedOrderNumber;\n})()\n}}",
            "issue_description": "={{\n(() => {\n  let currentDraft = null;\n\n  try {\n    currentDraft = $('Get Current Issue Draft').first().json;\n  } catch (e) {\n    currentDraft = null;\n  }\n\n  const existingDescription = String(\n    currentDraft?.issue_description || ''\n  ).trim();\n\n  const aiDescription = String(\n    $fromAI(\n      'issue_description',\n      'Write the complete updated Arabic description of the customer issue. Include all important facts explicitly provided by the customer. If an existing active collecting draft already has an issue_description, preserve all previous important facts and return one complete updated description that merges the previous information with the new information. Never remove previously confirmed details. Do not include image URLs. Do not invent facts.',\n      'string',\n      ''\n    ) || ''\n  ).trim();\n\n  // \u0625\u0630\u0627 \u0627\u0644\u0640Agent \u0631\u062c\u0639 \u0648\u0635\u0641 \u062c\u062f\u064a\u062f/\u0645\u062d\u062f\u062b \u0646\u0639\u062a\u0645\u062f\u0647\n  if (aiDescription) {\n    return aiDescription;\n  }\n\n  // \u062d\u0645\u0627\u064a\u0629: \u0644\u0627 \u0646\u0645\u0633\u062d \u0648\u0635\u0641 \u0645\u0648\u062c\u0648\u062f \u0628\u0633\u0628\u0628 \u0642\u064a\u0645\u0629 \u0641\u0627\u0631\u063a\u0629\n  if (existingDescription) {\n    return existingDescription;\n  }\n\n  throw new Error(\n    'issue_description is required when creating a new issue draft.'\n  );\n})()\n}}",
            "ticket_type\n": "={{\n(() => {\n  let currentDraft = null;\n\n  try {\n    currentDraft = $('Get Current Issue Draft').first().json;\n  } catch (e) {\n    currentDraft = null;\n  }\n\n  const existingTicketType = String(\n    currentDraft?.ticket_type || ''\n  ).trim();\n\n  const allowedTypes = [\n    'Complaint',\n    'Customer Request'\n  ];\n\n  // \u0625\u0630\u0627 \u0627\u0644\u0640Draft \u0627\u0644\u062d\u0627\u0644\u064a\u0629 \u0641\u064a\u0647\u0627 \u0646\u0648\u0639 \u0645\u0639\u062a\u0645\u062f \u0645\u0633\u0628\u0642\u064b\u0627\n  // \u0646\u062d\u0627\u0641\u0638 \u0639\u0644\u064a\u0647 \u0648\u0644\u0627 \u0646\u0637\u0644\u0628 \u0645\u0646 \u0627\u0644\u0640AI \u0625\u0639\u0627\u062f\u0629 \u062a\u0635\u0646\u064a\u0641\u0647\n  if (allowedTypes.includes(existingTicketType)) {\n    return existingTicketType;\n  }\n\n  // \u0625\u0630\u0627 Issue \u062c\u062f\u064a\u062f\u0629\u060c \u0646\u062e\u0644\u064a \u0627\u0644\u0640Agent \u064a\u062d\u062f\u062f \u0627\u0644\u0646\u0648\u0639\n  const aiTicketType = String(\n    $fromAI(\n      'ticket_type',\n      'Return exactly one approved Freshdesk ticket type for this issue: Complaint or Customer Request. Use Complaint for an actual customer problem, complaint, damage, missing item, quality issue, or service failure. Use Customer Request only for a customer request or service request that is not a complaint. Never invent another value.',\n      'string',\n      ''\n    ) || ''\n  ).trim();\n\n  if (allowedTypes.includes(aiTicketType)) {\n    return aiTicketType;\n  }\n\n  throw new Error(\n    'ticket_type must be exactly Complaint or Customer Request.'\n  );\n})()\n}}",
            "level_1\n": "={{\n(() => {\n  let currentDraft = null;\n\n  try {\n    currentDraft = $('Get Current Issue Draft').first().json;\n  } catch (e) {\n    currentDraft = null;\n  }\n\n  const existingTicketType = String(\n    currentDraft?.ticket_type || ''\n  ).trim();\n\n  const existingLevel1 = String(\n    currentDraft?.level_1 || ''\n  ).trim();\n\n  if (existingTicketType === 'Customer Request') {\n    return '';\n  }\n\n  const allowedLevel1 = [\n    'OPS',\n    'Logistic',\n    'Customer Service',\n    'IT Team',\n    'Company Policies'\n  ];\n\n  if (existingLevel1) {\n    if (!allowedLevel1.includes(existingLevel1)) {\n      throw new Error(\n        `Invalid existing level_1: ${existingLevel1}`\n      );\n    }\n\n    return existingLevel1;\n  }\n\n  const aiLevel1 = String(\n    $fromAI(\n      'level_1',\n      'For a Complaint, return exactly one approved Level 1 value: OPS, Logistic, Customer Service, IT Team, or Company Policies. Follow the complaint taxonomy and routing rules in the system prompt. For Customer Request return an empty string. Never invent, translate, rename, or approximate a classification.',\n      'string',\n      ''\n    ) || ''\n  ).trim();\n\n  if (!aiLevel1) {\n    return '';\n  }\n\n  if (!allowedLevel1.includes(aiLevel1)) {\n    throw new Error(\n      `Invalid level_1 returned by AI: ${aiLevel1}`\n    );\n  }\n\n  return aiLevel1;\n})()\n}}",
            "level_2\n": "={{\n(() => {\n  let currentDraft = null;\n\n  try {\n    currentDraft = $('Get Current Issue Draft').first().json;\n  } catch (e) {\n    currentDraft = null;\n  }\n\n  const existingTicketType = String(\n    currentDraft?.ticket_type || ''\n  ).trim();\n\n  const existingLevel2 = String(\n    currentDraft?.level_2 || ''\n  ).trim();\n\n  if (existingTicketType === 'Customer Request') {\n    return '';\n  }\n\n  const allowedLevel2 = [\n    'Laundry Invoicing Delay',\n    'Laundry Issue',\n    'Damaged Item - Laundry',\n    'Laundry Invoicing Error',\n    'Out-boarding Delay',\n    'Item Issue - Laundry',\n    'Bag Issue - Laundry',\n    'Other',\n\n    'Logistic Issue',\n    'Order Status',\n    'Bag Issue - Logistic',\n    'Driver Showing Bad Attitude',\n\n    'Slow responses to customer inquiries',\n    'Unprofessional or rude behavior',\n    'Customer complaint not resolved satisfactorily',\n    'Insufficient information provided to customer about service',\n\n    'UX/UI Issues',\n    'Order status not updated in system after delivery',\n    'Delay in customer notifications (SMS / WhatsApp)',\n    'Automated responses that are inappropriate or unclear',\n    'Payment Issues',\n\n    'Customer complains about delivery charges',\n    'Customer complains about increased laundry fees'\n  ];\n\n  if (existingLevel2) {\n    if (!allowedLevel2.includes(existingLevel2)) {\n      throw new Error(\n        `Invalid existing level_2: ${existingLevel2}`\n      );\n    }\n\n    return existingLevel2;\n  }\n\n  const aiLevel2 = String(\n    $fromAI(\n      'level_2',\n      'For a Complaint, return the exact approved Level 2 classification from the taxonomy in the system prompt. Return an empty string only when Level 2 does not apply or when the case is Customer Request. Never invent, translate, rename, or approximate a classification.',\n      'string',\n      ''\n    ) || ''\n  ).trim();\n\n  if (!aiLevel2) {\n    return '';\n  }\n\n  if (!allowedLevel2.includes(aiLevel2)) {\n    throw new Error(\n      `Invalid level_2 returned by AI: ${aiLevel2}`\n    );\n  }\n\n  return aiLevel2;\n})()\n}}",
            "level_3\n": "={{\n(() => {\n  let currentDraft = null;\n\n  try {\n    currentDraft = $('Get Current Issue Draft').first().json;\n  } catch (e) {\n    currentDraft = null;\n  }\n\n  const existingTicketType = String(\n    currentDraft?.ticket_type || ''\n  ).trim();\n\n  const existingLevel3 = String(\n    currentDraft?.level_3 || ''\n  ).trim();\n\n  if (existingTicketType === 'Customer Request') {\n    return '';\n  }\n\n  const forbiddenInternalValues = [\n    'Missing Items - Laundry - Found',\n    'Missing Items - Laundry - Not Found',\n    'Missing Items - Logistic - Found',\n    'Missing Items - Logistic - Not Found'\n  ];\n\n  const allowedLevel3 = [\n    'Spots',\n    'Irons - Laundry',\n    'Wet Clothes',\n    'Smell differences',\n    \"Didn't Follow The CST Request\",\n    'packaging issue',\n\n    'Color mixing',\n    'Damage to buttons or zippers',\n    'Damage to prints or embroidery',\n    'Fabric shrinkage',\n\n    'Missing Items - Laundry',\n    'Extra Items - Laundry',\n    'Mixing orders during sorting or packaging',\n\n    'Bag Not Received - Laundry',\n\n    'irons - Logistic',\n    'Missing Items - Logistic',\n    'Damaged Item - Logistic',\n    'Mixed order - Logistic',\n    'Extra Items - Logistic',\n    'The driver mixes the invoice',\n    'Clothes not hung properly',\n\n    'Pick-up Delay',\n    'updating order status',\n    'Delivery Delay',\n\n    'Bag not received - Logistic'\n  ];\n\n  if (existingLevel3) {\n    if (forbiddenInternalValues.includes(existingLevel3)) {\n      return '';\n    }\n\n    if (!allowedLevel3.includes(existingLevel3)) {\n      throw new Error(\n        `Invalid existing level_3: ${existingLevel3}`\n      );\n    }\n\n    return existingLevel3;\n  }\n\n  const aiLevel3 = String(\n    $fromAI(\n      'level_3',\n      'For a Complaint, return the exact approved Level 3 classification from the taxonomy in the system prompt when Level 3 applies. Never select any Found or Not Found missing-item outcome because those values are reserved for the responsible department after investigation. Return an empty string when Level 3 does not apply or when the case is Customer Request. Never invent, translate, rename, or approximate a classification.',\n      'string',\n      ''\n    ) || ''\n  ).trim();\n\n  if (!aiLevel3) {\n    return '';\n  }\n\n  if (forbiddenInternalValues.includes(aiLevel3)) {\n    throw new Error(\n      `The AI is not allowed to select internal outcome classification: ${aiLevel3}`\n    );\n  }\n\n  if (!allowedLevel3.includes(aiLevel3)) {\n    throw new Error(\n      `Invalid level_3 returned by AI: ${aiLevel3}`\n    );\n  }\n\n  return aiLevel3;\n})()\n}}",
            "status": "collecting",
            "created_at": "={{\n(() => {\n  let currentDraft = null;\n\n  try {\n    currentDraft = $('Get Current Issue Draft').first().json;\n  } catch (e) {\n    currentDraft = null;\n  }\n\n  const status = String(\n    currentDraft?.status || ''\n  ).trim().toLowerCase();\n\n  const isActive =\n    currentDraft?.is_active === true ||\n    String(currentDraft?.is_active || '').toLowerCase() === 'true';\n\n  const existingCreatedAt = String(\n    currentDraft?.created_at || ''\n  ).trim();\n\n  // \u0625\u0630\u0627 \u0646\u0641\u0633 \u0627\u0644\u0645\u0634\u0643\u0644\u0629 \u0645\u0627 \u0632\u0627\u0644\u062a collecting\n  // \u0646\u062d\u0627\u0641\u0638 \u0639\u0644\u0649 \u062a\u0627\u0631\u064a\u062e \u0625\u0646\u0634\u0627\u0626\u0647\u0627 \u0627\u0644\u0623\u0635\u0644\u064a\n  if (\n    isActive &&\n    status === 'collecting' &&\n    existingCreatedAt\n  ) {\n    return existingCreatedAt;\n  }\n\n  // \u0625\u0630\u0627 Issue \u062c\u062f\u064a\u062f\u0629\n  // \u0646\u0646\u0634\u0626 created_at \u062c\u062f\u064a\u062f\n  return $now\n    .setZone('Asia/Riyadh')\n    .toFormat('yyyy-MM-dd HH:mm:ss');\n})()\n}}",
            "updated_at": "={{ $now.setZone('Asia/Riyadh').toFormat('yyyy-MM-dd HH:mm:ss') }}",
            "conversation_internal_id": "={{ String($('Build Customer Context').first().json.conversation_internal_id || '').trim() }}",
            "user_id": "={{ String($('Build Customer Context').first().json.user_id || '').trim() }}",
            "customer_phone": "={{ String($('Build Customer Context').first().json.customer_phone || '').trim() }}",
            "is_active": "={{true}}",
            "image_urls": "={{\n(() => {\n\n  // ==================================================\n  // Parse image values safely\n  // ==================================================\n\n  function parseImages(value) {\n\n    if (Array.isArray(value)) {\n      return value;\n    }\n\n    if (value === null || value === undefined) {\n      return [];\n    }\n\n    const trimmed = String(value).trim();\n\n    if (!trimmed) {\n      return [];\n    }\n\n    try {\n\n      const parsed = JSON.parse(trimmed);\n\n      if (Array.isArray(parsed)) {\n        return parsed;\n      }\n\n      if (parsed) {\n        return [parsed];\n      }\n\n      return [];\n\n    } catch (e) {\n\n      return [trimmed];\n\n    }\n  }\n\n\n  // ==================================================\n  // Normalize image URL\n  // ==================================================\n\n  function normalizeUrl(value) {\n\n    let url = String(value || '').trim();\n\n    if (!url) {\n      return '';\n    }\n\n    // Supports Markdown format:\n    // [https://example.com/image.jpg](https://example.com/image.jpg)\n    const markdownMatch =\n      url.match(/\\((https?:\\/\\/[^)]+)\\)/i);\n\n    if (markdownMatch && markdownMatch[1]) {\n      url = markdownMatch[1].trim();\n    }\n\n    url = url\n      .replace(/^[\"']+|[\"']+$/g, '')\n      .trim();\n\n    if (!/^https?:\\/\\//i.test(url)) {\n      return '';\n    }\n\n    return url;\n  }\n\n\n  // ==================================================\n  // EXISTING images from current collecting Issue Draft\n  //\n  // IMPORTANT:\n  // Let the Agent pass the exact images it JUST received\n  // from Get Current Issue Draft.\n  // ==================================================\n\n  const existingImagesRaw = String(\n    $fromAI(\n      'save_issue_existing_image_urls',\n      `Return ONLY the complete image_urls JSON array from the SAME active collecting Issue Draft returned by Get Current Issue Draft in the CURRENT Agent execution.\n\nCRITICAL PRESERVATION RULE:\n\nIf Get Current Issue Draft returned status = collecting and its image_urls already contains one or more images, return EVERY existing image URL exactly as stored.\n\nA customer sending a text-only message, phone number, clarification, or any other information MUST NEVER cause existing images to be removed.\n\nIf existing images are present:\nNEVER return [].\n\nDo not invent image URLs.\nDo not shorten image URLs.\nDo not alter image URLs.\nDo not omit any existing image URL.\n\nReturn a JSON array only.\n\nExample:\n[\"https://example.com/1.jpg\",\"https://example.com/2.jpg\"]\n\nReturn exactly [] ONLY if Get Current Issue Draft genuinely returned no existing images.`,\n      'string',\n      '[]'\n    ) || '[]'\n  ).trim();\n\n\n  let existingImages =\n    parseImages(existingImagesRaw);\n\n\n  // ==================================================\n  // NEW images from current image batch\n  // ==================================================\n\n  let newImages = [];\n\n  try {\n\n    const batch =\n      $('Keep Latest Image Batch').first().json;\n\n    newImages =\n      parseImages(batch.image_urls);\n\n  } catch (e) {\n\n    newImages = [];\n\n  }\n\n\n  // ==================================================\n  // Fallback for images received in current context\n  // ==================================================\n\n  if (newImages.length === 0) {\n\n    try {\n\n      const context =\n        $('Build Customer Context').first().json;\n\n      newImages =\n        parseImages(context.image_urls);\n\n    } catch (e) {\n\n      newImages = [];\n\n    }\n  }\n\n\n  // ==================================================\n  // Preserve existing + add new + remove duplicates\n  // ==================================================\n\n  const allImages =\n    existingImages.concat(newImages);\n\n  const uniqueImages = [\n    ...new Set(\n      allImages\n        .map(normalizeUrl)\n        .filter(Boolean)\n    )\n  ];\n\n\n  // ==================================================\n  // Final value saved in Google Sheets\n  // ==================================================\n\n  return JSON.stringify(uniqueImages);\n\n})()\n}}",
            "order_phone": "={{\n(() => {\n  let existingOrderPhone = '';\n\n  try {\n    const draft = $('Get Current Issue Draft').first().json;\n\n    existingOrderPhone = String(\n      draft.order_phone || ''\n    )\n      .replace(/\\D/g, '')\n      .trim();\n  } catch (e) {\n    existingOrderPhone = '';\n  }\n\n  if (existingOrderPhone) {\n    return existingOrderPhone;\n  }\n\n  const aiPhone = $fromAI(\n    'order_phone',\n    'Return the exact confirmed phone number associated with the order ONLY when this issue is related to a specific order. If the order is on the same phone used in the current conversation, return that confirmed conversation phone. If it is on another phone, return only the exact alternate phone confirmed by the customer. Include the country code. For issues that do not require an order, including OTP/account creation issues and subscription payment issues, return an empty string. Never guess or invent a phone number.',\n    'string',\n    ''\n  );\n\n  return String(aiPhone || '')\n    .replace(/\\D/g, '')\n    .trim();\n})()\n}}"
          },
          "matchingColumns": [
            "issue_id"
          ],
          "schema": [
            {
              "id": "issue_id",
              "displayName": "issue_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "conversation_id",
              "displayName": "conversation_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "conversation_internal_id",
              "displayName": "conversation_internal_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "customer_phone",
              "displayName": "customer_phone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "order_number",
              "displayName": "order_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "order_phone",
              "displayName": "order_phone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "issue_description",
              "displayName": "issue_description",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "image_urls",
              "displayName": "image_urls",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "status",
              "displayName": "status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "is_active",
              "displayName": "is_active",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "ticket_id",
              "displayName": "ticket_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "updated_at",
              "displayName": "updated_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "ticket_type\n",
              "displayName": "ticket_type\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "level_1\n",
              "displayName": "level_1\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "level_2\n",
              "displayName": "level_2\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "level_3\n",
              "displayName": "level_3\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "department_resolution",
              "displayName": "department_resolution",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "resolution_message_sent",
              "displayName": "resolution_message_sent",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "is_final_resolution",
              "displayName": "is_final_resolution",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheetsTool",
      "typeVersion": 4.7,
      "position": [
        1472,
        2096
      ],
      "id": "d27ec57a-2c1c-419e-a4e5-58bdf565252b",
      "name": "Save Issue Draft",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "return [\n  {\n    json: {\n      buffer_update_completed: true\n    }\n  }\n];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        448,
        1456
      ],
      "id": "e44af68b-7dee-4149-9635-329fb2bd52f2",
      "name": "Continue Once After Buffer Update"
    },
    {
      "parameters": {
        "tableId": "image_buffer_test",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "message_id",
              "fieldValue": "={{ String($json.message_id ?? '') }}"
            },
            {
              "fieldId": "conversation_id",
              "fieldValue": "={{ String($json.conversation_id ?? '') }}"
            },
            {
              "fieldId": "image_urls",
              "fieldValue": "={{ JSON.stringify($json.image_urls ?? []) }}"
            },
            {
              "fieldId": "received_at",
              "fieldValue": "={{ DateTime.fromISO(\n  $('Normalize Freshchat Event').item.json.action_time ?? $now.toISO()\n).setZone('Asia/Riyadh').toFormat('yyyy-MM-dd HH:mm:ssZZ') }}"
            },
            {
              "fieldId": "conversation_internal_id",
              "fieldValue": "={{ String($json.conversation_internal_id ?? '') }}"
            },
            {
              "fieldId": "user_id",
              "fieldValue": "={{ String($json.user_id ?? '') }}"
            },
            {
              "fieldId": "customer_phone",
              "fieldValue": "={{ String($json.customer_phone ?? '') }}"
            },
            {
              "fieldId": "message_text",
              "fieldValue": "={{ String($json.customer_message ?? '') }}"
            },
            {
              "fieldId": "processed",
              "fieldValue": "false"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        -448,
        1248
      ],
      "id": "cb83a8f4-6131-412e-85fd-7162bd28e929",
      "name": "Save Message to Buffer1",
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "get",
        "tableId": "image_buffer_test",
        "filters": {
          "conditions": [
            {
              "keyName": "conversation_id",
              "keyValue": "={{ $json.conversation_id }}"
            },
            {
              "keyName": "processed",
              "keyValue": "false"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        0,
        1248
      ],
      "id": "14d70a5a-3041-4ca4-9ad7-604f7f49bd45",
      "name": "Get Unprocessed Image Buffer",
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const batch = $('Keep Latest Image Batch').first().json;\n\nconst bufferIds = Array.isArray(batch.buffer_ids)\n  ? batch.buffer_ids\n  : [];\n\nreturn bufferIds\n  .filter(id => id !== null && id !== undefined)\n  .map(id => ({\n    json: {\n      id: Number(id),\n      processed: true\n    }\n  }));"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        0,
        1456
      ],
      "id": "69909879-e4ce-47a8-b3df-d5072fac869c",
      "name": "Prepare Buffer IDs for Update"
    },
    {
      "parameters": {
        "operation": "update",
        "tableId": "image_buffer_test",
        "filters": {
          "conditions": [
            {
              "keyName": "id",
              "condition": "eq",
              "keyValue": "={{ $json.id }}"
            }
          ]
        },
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "processed",
              "fieldValue": "={{ $json.processed }}"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        224,
        1456
      ],
      "id": "9635f6fe-6204-48f6-ad75-780e3b550bf9",
      "name": "Mark Buffer Images as Processed",
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "getAll",
        "tableId": "image_buffer_test",
        "returnAll": true,
        "matchType": "allFilters",
        "filters": {
          "conditions": [
            {
              "keyName": "conversation_id",
              "condition": "eq",
              "keyValue": "={{ $('Build Customer Context').first().json.conversation_id }}"
            },
            {
              "keyName": "processed",
              "condition": "eq",
              "keyValue": "false"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        672,
        1264
      ],
      "id": "3ef7ce92-89ca-4bf0-9a51-afd90faec8b2",
      "name": "Get Pending Images Before Text",
      "alwaysOutputData": true,
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const rows = $input.all()\n  .map(item => item.json)\n  .filter(row => row && row.id !== undefined && row.id !== null);\n\n// \u0628\u064a\u0627\u0646\u0627\u062a \u0627\u0644\u0631\u0633\u0627\u0644\u0629 \u0627\u0644\u0646\u0635\u064a\u0629 \u0627\u0644\u062d\u0627\u0644\u064a\u0629\nconst context = $('Build Customer Context').first().json;\nconst event = $('Normalize Freshchat Event').first().json;\n\n// \u0648\u0642\u062a \u0627\u0644\u0631\u0633\u0627\u0644\u0629 \u0627\u0644\u0646\u0635\u064a\u0629 \u0627\u0644\u062d\u0627\u0644\u064a\u0629\nconst currentMessageTime =\n  Date.parse(String(event.action_time ?? '')) || Date.now();\n\n// \u0646\u0639\u062a\u0628\u0631 \u0627\u0644\u0635\u0648\u0631\u0629 \u0645\u0631\u062a\u0628\u0637\u0629 \u0628\u0627\u0644\u0646\u0635 \u0641\u0642\u0637 \u0625\u0630\u0627 \u0643\u0627\u0646\u062a \u0642\u0628\u0644 \u0627\u0644\u0646\u0635\n// \u0648\u0628\u0641\u0627\u0631\u0642 \u0644\u0627 \u064a\u062a\u062c\u0627\u0648\u0632 60 \u062b\u0627\u0646\u064a\u0629\nconst RECENT_WINDOW_MS = 60 * 1000;\n\nfunction parseImageUrls(value) {\n  if (Array.isArray(value)) {\n    return value;\n  }\n\n  if (!value) {\n    return [];\n  }\n\n  if (typeof value === 'string') {\n    try {\n      const parsed = JSON.parse(value);\n      return Array.isArray(parsed) ? parsed : [parsed];\n    } catch {\n      return [value];\n    }\n  }\n\n  return [];\n}\n\nconst recentPendingImages = rows.filter(row => {\n  // \u0644\u0627\u0632\u0645 \u064a\u0643\u0648\u0646 \u0627\u0644\u0635\u0641 \u063a\u064a\u0631 \u0645\u0639\u0627\u0644\u062c\n  if (row.processed !== false) {\n    return false;\n  }\n\n  // \u0644\u0627\u0632\u0645 \u064a\u062d\u062a\u0648\u064a \u0641\u0639\u0644\u064b\u0627 \u0639\u0644\u0649 \u0635\u0648\u0631\u0629\n  const images = parseImageUrls(row.image_urls);\n\n  if (images.length === 0) {\n    return false;\n  }\n\n  // \u0648\u0642\u062a \u0627\u0644\u0635\u0648\u0631\u0629\n  const imageTime = Date.parse(String(row.received_at ?? ''));\n\n  if (!Number.isFinite(imageTime)) {\n    return false;\n  }\n\n  const difference = currentMessageTime - imageTime;\n\n  // \u0627\u0644\u0635\u0648\u0631\u0629 \u0644\u0627\u0632\u0645 \u062a\u0643\u0648\u0646 \u0642\u0628\u0644 \u0627\u0644\u0646\u0635\n  // \u0648\u0636\u0645\u0646 \u0622\u062e\u0631 60 \u062b\u0627\u0646\u064a\u0629 \u0641\u0642\u0637\n  return (\n    difference >= 0 &&\n    difference <= RECENT_WINDOW_MS\n  );\n});\n\nreturn [\n  {\n    json: {\n      customer_phone: context.customer_phone ?? null,\n      customer_message: context.customer_message ?? '',\n      conversation_id: context.conversation_id ?? null,\n      conversation_internal_id:\n        context.conversation_internal_id ?? null,\n      user_id: context.user_id ?? null,\n      message_id: context.message_id ?? null,\n\n      has_recent_pending_image:\n        recentPendingImages.length > 0,\n\n      recent_pending_image_count:\n        recentPendingImages.length,\n\n      recent_pending_image_ids:\n        recentPendingImages.map(row => row.id),\n\n      recent_pending_message_ids:\n        recentPendingImages.map(row => row.message_id)\n    }\n  }\n];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        960,
        1264
      ],
      "id": "64333958-b6b4-4cc7-8bb6-9e7d89f7848e",
      "name": "Check Recent Pending Images"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "0156eebf-91dc-4026-8213-7d21280b6f47",
              "leftValue": "={{ $json.has_recent_pending_image }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -720,
        1664
      ],
      "id": "2d1ba5bd-a405-48d8-b665-ccb2d4624512",
      "name": "Recent Pending Image?"
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Marks an incomplete collecting issue as abandoned when the customer explicitly chooses to move to a different issue.",
        "operation": "update",
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "list",
          "cachedResultName": "Customer Service AI System",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit"
        },
        "sheetName": {
          "__rl": true,
          "value": 128263397,
          "mode": "list",
          "cachedResultName": "Issue Drafts",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit#gid=YOUR_SHEET_GID"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "status": "abandoned",
            "updated_at": "={{ $now.setZone('Asia/Riyadh').toFormat('yyyy-MM-dd HH:mm:ss') }}",
            "issue_id": "={{\n(() => {\n  let currentDraft = null;\n\n  try {\n    currentDraft = $('Get Current Issue Draft').first().json;\n  } catch (e) {\n    currentDraft = null;\n  }\n\n  const issueId = String(\n    currentDraft?.issue_id || ''\n  ).trim();\n\n  const status = String(\n    currentDraft?.status || ''\n  )\n    .trim()\n    .toLowerCase();\n\n  const isActive =\n    currentDraft?.is_active === true ||\n    String(currentDraft?.is_active || '')\n      .trim()\n      .toLowerCase() === 'true';\n\n  const ticketId = String(\n    currentDraft?.ticket_id || ''\n  ).trim();\n\n  if (!issueId) {\n    throw new Error(\n      'A valid current issue_id is required to abandon an issue draft.'\n    );\n  }\n\n  if (!isActive || status !== 'collecting') {\n    throw new Error(\n      'Only an active collecting issue draft can be abandoned.'\n    );\n  }\n\n  if (ticketId) {\n    throw new Error(\n      'An issue that already has a Freshdesk ticket cannot be abandoned.'\n    );\n  }\n\n  return issueId;\n})()\n}}",
            "is_active": "={{ false }}"
          },
          "matchingColumns": [
            "issue_id"
          ],
          "schema": [
            {
              "id": "issue_id",
              "displayName": "issue_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "conversation_id",
              "displayName": "conversation_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "conversation_internal_id",
              "displayName": "conversation_internal_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "customer_phone",
              "displayName": "customer_phone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "order_number",
              "displayName": "order_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "order_phone",
              "displayName": "order_phone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "issue_description",
              "displayName": "issue_description",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "image_urls",
              "displayName": "image_urls",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "status",
              "displayName": "status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "is_active",
              "displayName": "is_active",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "ticket_id",
              "displayName": "ticket_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "updated_at",
              "displayName": "updated_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "ticket_type\n",
              "displayName": "ticket_type\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_1\n",
              "displayName": "level_1\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_2\n",
              "displayName": "level_2\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_3\n",
              "displayName": "level_3\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "department_resolution",
              "displayName": "department_resolution",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "resolution_message_sent",
              "displayName": "resolution_message_sent",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "is_final_resolution",
              "displayName": "is_final_resolution",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "row_number",
              "displayName": "row_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "readOnly": true,
              "removed": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheetsTool",
      "typeVersion": 4.7,
      "position": [
        1600,
        2096
      ],
      "id": "f73da9f9-c166-4b88-8897-4b57c08af27f",
      "name": "Abandon Current Issue Draft",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-3.5-turbo",
          "mode": "list",
          "cachedResultName": "gpt-3.5-turbo"
        },
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        1824,
        2288
      ],
      "id": "ea0a3acc-b867-435c-a2dc-676c9e8f0117",
      "name": "OpenAI Chat Model1",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "list",
          "cachedResultName": "Customer Service AI System",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit"
        },
        "sheetName": {
          "__rl": true,
          "value": 128263397,
          "mode": "list",
          "cachedResultName": "Issue Drafts",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit#gid=YOUR_SHEET_GID"
        },
        "filtersUI": {
          "values": [
            {
              "lookupColumn": "conversation_id",
              "lookupValue": "={{ $('Build Customer Context').item.json.conversation_id }}"
            },
            {
              "lookupColumn": "status",
              "lookupValue": "=awaiting_customer_reply"
            },
            {
              "lookupColumn": "is_active",
              "lookupValue": "={{ true }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        -224,
        1648
      ],
      "id": "5174ee13-2a4e-4fb4-abef-3c881ccc766a",
      "name": "Find Awaiting Customer Reply Issue",
      "alwaysOutputData": true,
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "c0972dfd-11c6-421f-bd0f-0714767bc319",
              "leftValue": "={{ $json.status }}",
              "rightValue": "awaiting_customer_reply",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -720,
        1840
      ],
      "id": "f6c39b85-6d6f-4102-922a-c3890187c1ee",
      "name": "Has Awaiting Customer Reply Issue?"
    },
    {
      "parameters": {
        "inputText": "=\u0631\u0633\u0627\u0644\u0629 \u0627\u0644\u0639\u0645\u064a\u0644 \u0627\u0644\u062d\u0627\u0644\u064a\u0629:\n{{ $json.current_message }}\n\n\u0627\u0644\u0645\u0634\u0643\u0644\u0629 \u0623\u0648 \u0627\u0644\u0637\u0644\u0628 \u0627\u0644\u0623\u0635\u0644\u064a:\n{{ $json.issue_description }}\n\n\u0642\u0631\u0627\u0631 \u0627\u0644\u0642\u0633\u0645 \u0627\u0644\u0645\u062e\u062a\u0635:\n{{ $json.department_resolution }}\n\n\u0622\u062e\u0631 \u0631\u0633\u0627\u0644\u0629 \u0623\u0631\u0633\u0644\u0646\u0627\u0647\u0627 \u0644\u0644\u0639\u0645\u064a\u0644 \u0628\u062e\u0635\u0648\u0635 \u0627\u0644\u062d\u0644:\n{{ $json.resolution_message_sent }}",
        "categories": {
          "categories": [
            {
              "category": "related",
              "description": "=Choose this category when the customer's current message is related to the active issue, the department resolution, or the resolution message previously sent to the customer.\n\nExamples include:\n- accepting or agreeing with the resolution\n- rejecting or objecting to the resolution\n- expressing dissatisfaction with the resolution\n- answering a question we asked in the resolution message\n- providing a requested time, date, address, image, confirmation, or other requested information\n- asking for clarification about the resolution\n- asking a follow-up question about the same issue or proposed solution\n- saying things such as \"\u062a\u0645\u0627\u0645\", \"\u0645\u0648\u0627\u0641\u0642\", \"\u0644\u0627 \u0645\u0627 \u064a\u0646\u0627\u0633\u0628\u0646\u064a\", \"\u0628\u0643\u0631\u0629 \u0627\u0644\u0633\u0627\u0639\u0629 5\", when they clearly respond to the previous resolution message\n\nClassify based on the full context, not the customer message alone."
            },
            {
              "category": "unrelated",
              "description": "=Choose this category when the customer's current message is a new or separate topic and does not respond to the active issue or the resolution previously sent.\n\nExamples:\n- asking about Demo Laundry packages\n- asking about bag price or size\n- asking about branches\n- asking about another order\n- asking a general Demo Laundry question unrelated to the active issue\n- greeting or starting a different topic without responding to the resolution\n\nDo not classify a message as related only because the customer currently has an active issue."
            },
            {
              "category": "mixed",
              "description": "=Choose this category when the same customer message contains BOTH:\n\n1. a response or follow-up related to the active resolution\nAND\n2. a separate new question or topic unrelated to that resolution.\n\nExample:\n\"\u062a\u0645\u0627\u0645 \u0627\u0644\u062a\u0639\u0648\u064a\u0636 \u0645\u0646\u0627\u0633\u0628\u060c \u0648\u0628\u0627\u0644\u0645\u0646\u0627\u0633\u0628\u0629 \u0643\u0645 \u0633\u0639\u0631 \u0634\u0646\u0637\u0629 \u0643\u0644\u064a\u0646\u061f\"\n\nExample:\n\"\u0628\u0643\u0631\u0629 \u0627\u0644\u0633\u0627\u0639\u0629 5 \u0645\u0646\u0627\u0633\u0628\u060c \u0648\u0639\u0646\u062f\u064a \u0633\u0624\u0627\u0644 \u062b\u0627\u0646\u064a \u0643\u0645 \u0633\u0639\u0631 \u0628\u0627\u0642\u0629 299\u061f\"\n\nUse mixed only when both parts clearly exist in the same message."
            }
          ]
        },
        "options": {
          "systemPromptTemplate": "=You are a strict routing classifier for Demo Laundry Customer Service.\n\nYour ONLY task is to classify the customer's CURRENT message into exactly one of the available categories.\n\nAvailable categories:\n{categories}\n\nUse the FULL context provided in the text:\n- the customer's current message\n- the original issue/request\n- the department resolution\n- the last resolution message sent to the customer\n\nCLASSIFICATION RULES:\n\n1. Do NOT classify a message as related only because an active issue exists.\n\n2. Choose \"related\" when the current message clearly:\n- responds to the resolution\n- accepts or rejects the resolution\n- answers a question asked in the resolution message\n- provides requested information\n- asks about the same issue or resolution\n- expresses satisfaction or dissatisfaction with the proposed solution\n\n3. Short replies must be interpreted using the previous resolution message.\nExamples:\n- \"\u0628\u0643\u0631\u0629 \u0627\u0644\u0633\u0627\u0639\u0629 5\" is related if the previous message asked for a suitable time.\n- \"\u0644\u0627 \u0645\u0627 \u064a\u0646\u0627\u0633\u0628\u0646\u064a\" is related if the previous message proposed a resolution.\n- \"\u062a\u0645\u0627\u0645 \u0645\u0648\u0627\u0641\u0642\" is related if it clearly accepts the resolution.\n\n4. Choose \"unrelated\" when the message starts or asks about a separate topic that does not respond to the active resolution.\n\nExample:\nPrevious resolution is about compensation.\nCurrent message: \"\u0643\u0645 \u0633\u0639\u0631 \u0634\u0646\u0637\u0629 \u0643\u0644\u064a\u0646\u061f\"\n\u2192 unrelated\n\n5. Choose \"mixed\" ONLY when the SAME current message clearly contains BOTH:\n- a response related to the active resolution\nAND\n- a separate new topic/question.\n\nExample:\n\"\u0627\u0644\u062a\u0639\u0648\u064a\u0636 \u0645\u0646\u0627\u0633\u0628\u060c \u0648\u0628\u0627\u0644\u0645\u0646\u0627\u0633\u0628\u0629 \u0643\u0645 \u0633\u0639\u0631 \u0634\u0646\u0637\u0629 \u0643\u0644\u064a\u0646\u061f\"\n\u2192 mixed\n\n6. If the message does not clearly connect to the resolution and does not answer anything requested in the previous resolution message, prefer \"unrelated\".\n\n7. Never answer the customer.\nNever explain the classification.\nOnly classify according to the available categories."
        }
      },
      "type": "@n8n/n8n-nodes-langchain.textClassifier",
      "typeVersion": 1.1,
      "position": [
        -720,
        2320
      ],
      "id": "d375e7f8-63e2-446e-b970-9724434e4a5f",
      "name": "Classify Customer Reply to Resolution"
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-5-nano",
          "mode": "list",
          "cachedResultName": "gpt-5-nano"
        },
        "responsesApiEnabled": false,
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        -720,
        2544
      ],
      "id": "f73986c6-0dc9-446d-a217-79d2f1c5211b",
      "name": "OpenAI Chat Model3",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-5-nano",
          "mode": "list",
          "cachedResultName": "gpt-5-nano"
        },
        "responsesApiEnabled": false,
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        2896,
        2544
      ],
      "id": "6cdbeb47-c2e5-495f-99b8-d1548f5d28ad",
      "name": "OpenAI Chat Model4",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "inputText": "=\u0631\u0633\u0627\u0644\u0629 \u0627\u0644\u0639\u0645\u064a\u0644 \u0627\u0644\u062d\u0627\u0644\u064a\u0629:\n{{ $json.current_message || $('Prepare Agent Input').first().json.agent_input }}\n\u0627\u0644\u0645\u0634\u0643\u0644\u0629 \u0623\u0648 \u0627\u0644\u0637\u0644\u0628 \u0627\u0644\u0623\u0635\u0644\u064a:\n{{ $json.issue_description }}\n\n\u0642\u0631\u0627\u0631 \u0627\u0644\u0642\u0633\u0645 \u0627\u0644\u0645\u062e\u062a\u0635:\n{{ $json.department_resolution }}\n\n\u0622\u062e\u0631 \u0631\u0633\u0627\u0644\u0629 \u0623\u0631\u0633\u0644\u0646\u0627\u0647\u0627 \u0644\u0644\u0639\u0645\u064a\u0644 \u0628\u062e\u0635\u0648\u0635 \u0627\u0644\u062d\u0644:\n{{ $json.resolution_message_sent }}",
        "categories": {
          "categories": [
            {
              "category": "accepted",
              "description": "=Choose this category ONLY when the customer clearly accepts, agrees with, or confirms the approved resolution AND there is no specific information, selection, or confirmation still required from the customer.\n\nExamples:\n\n- \"\u062a\u0645\u0627\u0645\"\n- \"\u0645\u0648\u0627\u0641\u0642\"\n- \"\u0627\u0648\u0643\u064a \u0645\u0646\u0627\u0633\u0628\"\n- \"\u064a\u0639\u0637\u064a\u0643\u0645 \u0627\u0644\u0639\u0627\u0641\u064a\u0629 \u062a\u0645\u0627\u0645\"\n- \"\u062e\u0644\u0627\u0635 \u0645\u0648\u0627\u0641\u0642 \u0639\u0644\u0649 \u0627\u0644\u062a\u0639\u0648\u064a\u0636\"\n- \"\u062a\u0645\u0627\u0645 \u0643\u0630\u0627 \u0645\u0646\u0627\u0633\u0628\"\n\nChoose accepted ONLY when the customer's reply means the resolution is fully accepted and nothing else is currently required from the customer.\n\nDo NOT choose this category if the customer:\n\n- rejects the resolution\n- complains about the resolution\n- asks for a different solution\n- asks for additional compensation\n- asks a question about the resolution\n- provides information that we specifically requested\n- is responding to a request to choose or confirm specific information\n- still needs to provide a required time, period, date, address, confirmation, or other requested detail\n\nIMPORTANT:\n\nIf the previous resolution message asked the customer to provide, select, or confirm specific information, do NOT classify short confirmations such as:\n\n- \"\u062a\u0645\u0627\u0645\"\n- \"\u0627\u0648\u0643\u064a\"\n- \"\u0627\u0639\u062a\u0645\u062f\u0648\u0647\u0627\"\n- \"\u0645\u0648\u0627\u0641\u0642\"\n- \"\u0627\u064a \u0646\u0639\u0645\"\n\nas accepted.\n\nInstead, classify them as provided_requested_info so the next validation step can determine whether the required information or confirmation is complete and valid.\n\nExamples:\n\nPrevious message:\n\"\u0627\u062e\u062a\u0631 \u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u0645\u0646\u0627\u0633\u0628\u0629 \u0644\u0644\u0627\u0633\u062a\u0644\u0627\u0645: 11-3\u060c 4-7\u060c \u0623\u0648 8-10.\"\n\nCustomer:\n\"\u062a\u0645\u0627\u0645\"\n\u2192 provided_requested_info\n\nCustomer:\n\"\u0627\u0639\u062a\u0645\u062f\u0648\u0647\u0627\"\n\u2192 provided_requested_info\n\nPrevious message:\n\"\u0647\u0644 \u0646\u0639\u062a\u0645\u062f \u0644\u0643 \u0627\u0644\u0641\u062a\u0631\u0629 \u0645\u0646 4 \u0625\u0644\u0649 7 \u0645\u0633\u0627\u0621\u064b\u061f\"\n\nCustomer:\n\"\u062a\u0645\u0627\u0645 \u0627\u0639\u062a\u0645\u062f\u0648\u0647\u0627\"\n\u2192 provided_requested_info\n\nPrevious message:\n\"\u062a\u0645 \u0625\u0636\u0627\u0641\u0629 30 \u0631\u064a\u0627\u0644 \u0625\u0644\u0649 \u0645\u062d\u0641\u0638\u062a\u0643.\"\n\nCustomer:\n\"\u062a\u0645\u0627\u0645\u060c \u0634\u0643\u0631\u0627\u064b\"\n\u2192 accepted\n\nThe customer must clearly be accepting a completed resolution as it is, with no requested information or confirmation still pending."
            },
            {
              "category": "provided_requested_info",
              "description": "=Choose this category when the customer provides OR ATTEMPTS TO PROVIDE information, a selection, or a confirmation that was requested in the previous resolution message.\n\nThis category includes both:\n- complete and valid requested information\n- incomplete, vague, or potentially invalid attempts to provide the requested information\n\nThe next validation step will determine whether the information is actually valid and sufficient.\n\nExamples include:\n\n- choosing or attempting to choose a re-service pickup period\n- providing a specific pickup time\n- providing a date\n- confirming availability\n- confirming an address\n- providing requested details\n- answering a direct question asked in the resolution message\n- confirming a specific option previously proposed to the customer\n\nIMPORTANT RE-SERVICE SCHEDULING RULE:\n\nIf the previous resolution message asks the customer to choose a pickup period for re-service, ANY reply that attempts to select or schedule the pickup must be classified as provided_requested_info, even if the time is vague, invalid, or outside the approved periods.\n\nApproved pickup periods are:\n\n- 11:00 AM to 3:00 PM\n- 4:00 PM to 7:00 PM\n- 8:00 PM to 10:00 PM\n\nExamples:\n\nPrevious message:\n\"\u0627\u062e\u062a\u0631 \u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u0645\u0646\u0627\u0633\u0628\u0629 \u0644\u0643 \u0644\u0644\u0627\u0633\u062a\u0644\u0627\u0645:\n\u2022 \u0645\u0646 11:00 \u0635\u0628\u0627\u062d\u064b\u0627 \u0625\u0644\u0649 3:00 \u0639\u0635\u0631\u064b\u0627\n\u2022 \u0645\u0646 4:00 \u0639\u0635\u0631\u064b\u0627 \u0625\u0644\u0649 7:00 \u0645\u0633\u0627\u0621\u064b\n\u2022 \u0645\u0646 8:00 \u0645\u0633\u0627\u0621\u064b \u0625\u0644\u0649 10:00 \u0645\u0633\u0627\u0621\u064b\"\n\nCustomer:\n\"\u0645\u0646 4 \u0625\u0644\u0649 7\"\n\u2192 provided_requested_info\n\nCustomer:\n\"\u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u062b\u0627\u0646\u064a\u0629\"\n\u2192 provided_requested_info\n\nCustomer:\n\"\u0627\u0644\u0633\u0627\u0639\u0629 5\"\n\u2192 provided_requested_info\n\nCustomer:\n\"\u062a\u0639\u0627\u0644\u0648\u0627 \u0627\u0644\u0622\u0646\"\n\u2192 provided_requested_info\n\nCustomer:\n\"\u0627\u0644\u0633\u0627\u0639\u0629 3:30\"\n\u2192 provided_requested_info\n\nCustomer:\n\"\u0628\u0639\u062f \u0634\u0648\u064a\"\n\u2192 provided_requested_info\n\nThese responses must NOT be classified as asks_about_resolution.\nThe validation step will determine whether the provided time or selection is valid.\n\nCONFIRMATION RULE:\n\nIf the previous message asked the customer to provide, select, or confirm specific information, short confirmations must also go to provided_requested_info.\n\nExample:\n\nPrevious message:\n\"\u0647\u0644 \u0646\u0639\u062a\u0645\u062f \u0644\u0643 \u0627\u0644\u0641\u062a\u0631\u0629 \u0645\u0646 4 \u0625\u0644\u0649 7 \u0645\u0633\u0627\u0621\u064b\u061f\"\n\nCustomer:\n\"\u062a\u0645\u0627\u0645 \u0627\u0639\u062a\u0645\u062f\u0648\u0647\u0627\"\n\u2192 provided_requested_info\n\nCustomer:\n\"\u0646\u0639\u0645\"\n\u2192 provided_requested_info\n\nIf the previous message requested information but the customer replies only:\n\"\u062a\u0645\u0627\u0645\"\n\"\u0627\u0648\u0643\u064a\"\n\"\u0645\u0648\u0627\u0641\u0642\"\n\"\u0627\u0639\u062a\u0645\u062f\u0648\u0647\u0627\"\n\nand no specific option was previously proposed, still choose provided_requested_info.\nThe next validation step will determine whether the response is complete enough.\n\nOTHER REQUESTED INFORMATION:\n\nPrevious message:\n\"\u0645\u0645\u0643\u0646 \u062a\u0623\u0643\u062f \u0644\u064a \u0639\u0646\u0648\u0627\u0646 \u0627\u0644\u0627\u0633\u062a\u0644\u0627\u0645\u061f\"\n\nCustomer:\n\"\u0646\u0641\u0633 \u0627\u0644\u0639\u0646\u0648\u0627\u0646 \u0627\u0644\u0645\u0633\u062c\u0644\"\n\u2192 provided_requested_info\n\nChoose provided_requested_info whenever the customer is responding to a request for information, selection, or confirmation.\n\nDo NOT choose this category when:\n\n- the customer is only asking a question about the resolution\n- the customer is asking how the resolution works\n- the customer is rejecting the resolution\n- the customer requests a different solution\n- the customer requests additional compensation\n\nExamples:\n\n\"\u0643\u0645 \u062a\u0633\u062a\u063a\u0631\u0642 \u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u062e\u062f\u0645\u0629\u061f\"\n\u2192 asks_about_resolution\n\n\"\u0647\u0644 \u0627\u0644\u0627\u0633\u062a\u0644\u0627\u0645 \u0645\u062c\u0627\u0646\u064a\u061f\"\n\u2192 asks_about_resolution\n\n\"\u0645\u0627 \u0623\u0628\u063a\u0649 \u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u062e\u062f\u0645\u0629\u060c \u0623\u0628\u063a\u0649 \u062a\u0639\u0648\u064a\u0636\"\n\u2192 needs_review\n\n\"\u0627\u0644\u062a\u0639\u0648\u064a\u0636 \u0642\u0644\u064a\u0644\"\n\u2192 needs_review"
            },
            {
              "category": "needs_review",
              "description": "=Choose this category when the customer's response means the approved resolution needs to be reviewed again by the responsible team.\n\nThis includes when the customer:\n\n- rejects the resolution\n- says the resolution is not acceptable\n- is dissatisfied or angry about the resolution\n- asks for a different solution\n- requests additional compensation\n- asks for a higher compensation amount\n- requests an additional action that was not approved in the current resolution\n- disputes what Demo Laundry offered\n- says the proposed solution does not solve the issue\n- refuses the proposed action\n\nExamples:\n\nResolution:\n\"\u062a\u0645 \u0627\u0639\u062a\u0645\u0627\u062f \u062a\u0639\u0648\u064a\u0636\u0643 \u0628\u0645\u0628\u0644\u063a 30 \u0631\u064a\u0627\u0644.\"\n\nCustomer:\n\"\u0644\u0627\u060c 30 \u0631\u064a\u0627\u0644 \u0645\u0648 \u0645\u0642\u0628\u0648\u0644\"\n\u2192 needs_review\n\nCustomer:\n\"\u0623\u0628\u063a\u0649 \u062a\u0639\u0648\u064a\u0636 \u0623\u0643\u0628\u0631\"\n\u2192 needs_review\n\nCustomer:\n\"\u0647\u0630\u0627 \u0627\u0644\u062d\u0644 \u0645\u0627 \u064a\u0646\u0627\u0633\u0628\u0646\u064a\"\n\u2192 needs_review\n\nResolution:\n\"\u062a\u0645 \u0627\u0639\u062a\u0645\u0627\u062f \u0625\u0639\u0627\u062f\u0629 \u062e\u062f\u0645\u0629 \u0627\u0644\u0643\u0648\u064a \u0644\u0643 \u0628\u062f\u0648\u0646 \u062a\u0643\u0644\u0641\u0629.\"\n\nCustomer:\n\"\u0643\u0648\u064a \u0628\u0633 \u0623\u0628\u063a\u0649 \u062a\u0639\u0648\u064a\u0636 \u062a\u0623\u062e\u064a\u0631 \u0627\u0644\u0648\u0642\u062a \u062d\u0642\u064a\"\n\u2192 needs_review\n\nCustomer:\n\"\u0644\u0627 \u0645\u0627 \u0623\u0628\u063a\u0649 \u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u062e\u062f\u0645\u0629\"\n\u2192 needs_review\n\nIMPORTANT:\nNever assume or approve a new solution yourself.\nIf the customer requests anything beyond the currently approved resolution, classify it as needs_review so the issue can be returned to the responsible team."
            },
            {
              "category": "asks_about_resolution",
              "description": "=Choose this category when the customer asks a question or requests clarification about the approved resolution without clearly rejecting it or requesting a different resolution.\n\nExamples:\n- asking how the approved resolution will work\n- asking when the approved action will happen\n- asking what the resolution means\n- asking what happens next\n- asking a clarification about the approved compensation or service\n- asking a question directly related to the solution\n\nExamples:\n\nResolution:\n\"\u062a\u0645 \u0627\u0639\u062a\u0645\u0627\u062f \u062a\u0639\u0648\u064a\u0636\u0643 \u0628\u0645\u0628\u0644\u063a 30 \u0631\u064a\u0627\u0644.\"\n\nCustomer:\n\"\u0645\u062a\u0649 \u064a\u0646\u0632\u0644 \u0627\u0644\u062a\u0639\u0648\u064a\u0636\u061f\"\n\u2192 asks_about_resolution\n\nCustomer:\n\"\u0648\u064a\u0646 \u064a\u0646\u0636\u0627\u0641 \u0627\u0644\u0645\u0628\u0644\u063a\u061f\"\n\u2192 asks_about_resolution\n\nResolution:\n\"\u062a\u0645 \u0627\u0639\u062a\u0645\u0627\u062f \u0625\u0639\u0627\u062f\u0629 \u062e\u062f\u0645\u0629 \u0627\u0644\u0643\u0648\u064a \u0644\u0643 \u0628\u062f\u0648\u0646 \u062a\u0643\u0644\u0641\u0629.\"\n\nCustomer:\n\"\u0643\u064a\u0641 \u0628\u062a\u0643\u0648\u0646 \u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u062e\u062f\u0645\u0629\u061f\"\n\u2192 asks_about_resolution\n\nCustomer:\n\"\u0647\u0644 \u0628\u062a\u062c\u0648\u0646 \u062a\u0633\u062a\u0644\u0645\u0648\u0646 \u0627\u0644\u0642\u0637\u0639\u0629\u061f\"\n\u2192 asks_about_resolution\n\nDo NOT choose this category if the customer is clearly rejecting the resolution or requesting an additional/different solution. In that case choose needs_review."
            }
          ]
        },
        "options": {
          "systemPromptTemplate": "=Choose this category when the customer asks a question or requests clarification about the approved resolution without clearly rejecting it or requesting a different resolution.\n\nExamples:\n- asking how the approved resolution will work\n- asking when the approved action will happen\n- asking what the resolution means\n- asking what happens next\n- asking a clarification about the approved compensation or service\n- asking a question directly related to the solution\n\nExamples:\n\nResolution:\n\"\u062a\u0645 \u0627\u0639\u062a\u0645\u0627\u062f \u062a\u0639\u0648\u064a\u0636\u0643 \u0628\u0645\u0628\u0644\u063a 30 \u0631\u064a\u0627\u0644.\"\n\nCustomer:\n\"\u0645\u062a\u0649 \u064a\u0646\u0632\u0644 \u0627\u0644\u062a\u0639\u0648\u064a\u0636\u061f\"\n\u2192 asks_about_resolution\n\nCustomer:\n\"\u0648\u064a\u0646 \u064a\u0646\u0636\u0627\u0641 \u0627\u0644\u0645\u0628\u0644\u063a\u061f\"\n\u2192 asks_about_resolution\n\nResolution:\n\"\u062a\u0645 \u0627\u0639\u062a\u0645\u0627\u062f \u0625\u0639\u0627\u062f\u0629 \u062e\u062f\u0645\u0629 \u0627\u0644\u0643\u0648\u064a \u0644\u0643 \u0628\u062f\u0648\u0646 \u062a\u0643\u0644\u0641\u0629.\"\n\nCustomer:\n\"\u0643\u064a\u0641 \u0628\u062a\u0643\u0648\u0646 \u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u062e\u062f\u0645\u0629\u061f\"\n\u2192 asks_about_resolution\n\nCustomer:\n\"\u0647\u0644 \u0628\u062a\u062c\u0648\u0646 \u062a\u0633\u062a\u0644\u0645\u0648\u0646 \u0627\u0644\u0642\u0637\u0639\u0629\u061f\"\n\u2192 asks_about_resolution\n\nDo NOT choose this category if the customer is clearly rejecting the resolution or requesting an additional/different solution. In that case choose needs_review."
        }
      },
      "type": "@n8n/n8n-nodes-langchain.textClassifier",
      "typeVersion": 1.1,
      "position": [
        2816,
        2256
      ],
      "id": "4d3296e8-13c5-41e4-a14a-8d77f27ebb93",
      "name": "Classify Related Resolution Reply"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://YOUR_FRESHDESK_DOMAIN.freshdesk.com/api/v2/tickets/{{ $json.ticket_id }}/notes",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"body\": {{ JSON.stringify(\"\u0631\u062f \u0627\u0644\u0639\u0645\u064a\u0644 \u0639\u0644\u0649 \u0627\u0644\u062d\u0644 \u0627\u0644\u0633\u0627\u0628\u0642:<br><br>\" + ($json.current_message || $('Prepare Agent Input').first().json.agent_input)) }},\n  \"private\": true\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        4176,
        2688
      ],
      "id": "bd8447eb-f593-4d90-aae8-7fc93ded83d0",
      "name": "Add Customer Reply to Ticket",
      "credentials": {
        "httpBasicAuth": {
          "name": "<your credential>"
        },
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "update",
        "ticketId": "={{ $json.ticket_id }}",
        "updateFields": {
          "status": "pending"
        }
      },
      "type": "n8n-nodes-base.freshdesk",
      "typeVersion": 1,
      "position": [
        4464,
        2688
      ],
      "id": "7b2a83bf-74b1-41e6-9429-f39036d20877",
      "name": "Set Ticket Back to Pending",
      "credentials": {
        "freshdeskApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://YOUR_FRESHCHAT_DOMAIN.freshchat.com/v2/conversations/{{ $('Normalize Freshchat Event').item.json.conversation_id }}/messages",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_API_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Accept",
              "value": "application/json"
            },
            {
              "name": "ASSUME-IDENTITY",
              "value": "false"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"message_parts\": [\n    {\n      \"text\": {\n        \"content\": \"\u0648\u0635\u0644 \u0637\u0644\u0628\u0643\u060c \u0648\u062a\u0645 \u0631\u0641\u0639\u0647 \u0644\u0644\u0641\u0631\u064a\u0642 \u0627\u0644\u0645\u062e\u062a\u0635 \u0644\u0644\u0645\u0631\u0627\u062c\u0639\u0629. \u0628\u0646\u0631\u062c\u0639 \u0644\u0643 \u0623\u0648\u0644 \u0645\u0627 \u064a\u062a\u0645 \u0627\u0644\u062a\u062d\u062f\u064a\u062b \ud83d\ude4f\"\n      }\n    }\n  ],\n  \"message_type\": \"normal\",\n  \"actor_type\": \"bot\"\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        4688,
        2688
      ],
      "id": "13e6982d-cf9f-4aca-aa0b-b83b79e66e15",
      "name": "Send Review Confirmation to Customer"
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "list",
          "cachedResultName": "Customer Service AI System",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit"
        },
        "sheetName": {
          "__rl": true,
          "value": 128263397,
          "mode": "list",
          "cachedResultName": "Issue Drafts",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit#gid=YOUR_SHEET_GID"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "issue_id": "={{ $('Classify Related Resolution Reply').item.json.issue_id }}",
            "updated_at": "={{ $now.setZone('Asia/Riyadh').toFormat('yyyy-MM-dd HH:mm:ss') }}",
            "status": "=pending",
            "is_active": "={{ true }}"
          },
          "matchingColumns": [
            "issue_id"
          ],
          "schema": [
            {
              "id": "issue_id",
              "displayName": "issue_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "conversation_id",
              "displayName": "conversation_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "conversation_internal_id",
              "displayName": "conversation_internal_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "customer_phone",
              "displayName": "customer_phone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "order_number",
              "displayName": "order_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "order_phone",
              "displayName": "order_phone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "issue_description",
              "displayName": "issue_description",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "image_urls",
              "displayName": "image_urls",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "status",
              "displayName": "status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "is_active",
              "displayName": "is_active",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "ticket_id",
              "displayName": "ticket_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "updated_at",
              "displayName": "updated_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "ticket_type\n",
              "displayName": "ticket_type\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_1\n",
              "displayName": "level_1\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_2\n",
              "displayName": "level_2\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_3\n",
              "displayName": "level_3\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "department_resolution",
              "displayName": "department_resolution",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "resolution_message_sent",
              "displayName": "resolution_message_sent",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "is_final_resolution",
              "displayName": "is_final_resolution",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "row_number",
              "displayName": "row_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "readOnly": true,
              "removed": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        4912,
        2688
      ],
      "id": "ff39653b-037c-473e-a825-a0411e129dd8",
      "name": "Set Issue Back to Pending",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://YOUR_FRESHCHAT_DOMAIN.freshchat.com/v2/conversations/{{ $('Normalize Freshchat Event').item.json.conversation_id }}/messages",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_API_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Accept",
              "value": "application/json"
            },
            {
              "name": "ASSUME-IDENTITY",
              "value": "false"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"message_parts\": [\n    {\n      \"text\": {\n        \"content\": \"\u0634\u0627\u0643\u0631\u064a\u0646 \u0644\u0643 \ud83d\ude4f \u0648\u0646\u0633\u0639\u062f \u0628\u062e\u062f\u0645\u062a\u0643 \u062f\u0627\u0626\u0645\u064b\u0627.\"\n      }\n    }\n  ],\n  \"message_type\": \"normal\",\n  \"actor_type\": \"bot\"\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        3824,
        1296
      ],
      "id": "2405865e-151c-4eff-8d6d-d8c3eeb4ea7c",
      "name": "Send Resolution Acceptance Confirmation"
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "list",
          "cachedResultName": "Customer Service AI System",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit"
        },
        "sheetName": {
          "__rl": true,
          "value": 128263397,
          "mode": "list",
          "cachedResultName": "Issue Drafts",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit#gid=YOUR_SHEET_GID"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "issue_id": "={{ $('Classify Related Resolution Reply').item.json.issue_id }}",
            "updated_at": "={{ $now.setZone('Asia/Riyadh').toFormat('yyyy-MM-dd HH:mm:ss') }}",
            "status": "=resolved",
            "is_active": "={{ false }}"
          },
          "matchingColumns": [
            "issue_id"
          ],
          "schema": [
            {
              "id": "issue_id",
              "displayName": "issue_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "conversation_id",
              "displayName": "conversation_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "conversation_internal_id",
              "displayName": "conversation_internal_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "customer_phone",
              "displayName": "customer_phone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "order_number",
              "displayName": "order_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "order_phone",
              "displayName": "order_phone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "issue_description",
              "displayName": "issue_description",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "image_urls",
              "displayName": "image_urls",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "status",
              "displayName": "status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "is_active",
              "displayName": "is_active",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "ticket_id",
              "displayName": "ticket_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "updated_at",
              "displayName": "updated_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "ticket_type\n",
              "displayName": "ticket_type\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_1\n",
              "displayName": "level_1\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_2\n",
              "displayName": "level_2\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_3\n",
              "displayName": "level_3\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "department_resolution",
              "displayName": "department_resolution",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "resolution_message_sent",
              "displayName": "resolution_message_sent",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "is_final_resolution",
              "displayName": "is_final_resolution",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "row_number",
              "displayName": "row_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "readOnly": true,
              "removed": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        4176,
        1296
      ],
      "id": "78cedef4-4025-42a5-bb58-b71be04cd274",
      "name": "Mark Issue Resolved After Acceptance",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://YOUR_FRESHDESK_DOMAIN.freshdesk.com/api/v2/tickets/{{ $('Classify Related Resolution Reply').first().json.ticket_id || $('Classify Related Resolution Reply').first().json['ticket_id '] }}/notes",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"body\": {{ JSON.stringify(\n    (() => {\n      const noteText = String($json.text || '').trim();\n\n      let images = [];\n\n      try {\n        const batch = $('Keep Latest Image Batch').first().json;\n\n        images = Array.isArray(batch.image_urls)\n          ? batch.image_urls\n          : [];\n      } catch (e) {\n        images = [];\n      }\n\n      const cleanImages = [\n        ...new Set(\n          images\n            .map(url => String(url || '').trim())\n            .filter(url => /^https?:\\/\\//i.test(url))\n        )\n      ];\n\n      const imagesHtml = cleanImages\n        .map(url =>\n          `<img src=\"${url}\" style=\"max-width:500px;height:auto;display:block;\"><br>`\n        )\n        .join('');\n\n      if (imagesHtml) {\n        return `<div>${noteText}</div><br>${imagesHtml}`;\n      }\n\n      return `<div>${noteText}</div>`;\n    })()\n  ) }},\n  \"private\": true\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        4464,
        1600
      ],
      "id": "f21edee7-15f1-423c-8c63-a9c5314fa87d",
      "name": "Add Requested Info to Ticket",
      "credentials": {
        "httpBasicAuth": {
          "name": "<your credential>"
        },
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "update",
        "ticketId": "={{ $json.ticket_id }}",
        "updateFields": {
          "status": "pending"
        }
      },
      "type": "n8n-nodes-base.freshdesk",
      "typeVersion": 1,
      "position": [
        4688,
        1600
      ],
      "id": "125ed68a-53d7-462b-a49b-6e14d5898704",
      "name": "Set Ticket Pending After Requested Info",
      "credentials": {
        "freshdeskApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://YOUR_FRESHCHAT_DOMAIN.freshchat.com/v2/conversations/{{ $('Normalize Freshchat Event').item.json.conversation_id }}/messages",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_API_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Accept",
              "value": "application/json"
            },
            {
              "name": "ASSUME-IDENTITY",
              "value": "false"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"message_parts\": [\n    {\n      \"text\": {\n        \"content\": \"\u0648\u0635\u0644\u0646\u0627 \u0631\u062f\u0643\u060c \u0634\u0643\u0631\u064b\u0627 \u0644\u0643 \ud83d\ude4f \u0648\u0628\u0646\u0643\u0645\u0644 \u0644\u0643 \u0627\u0644\u0625\u062c\u0631\u0627\u0621.\"\n      }\n    }\n  ],\n  \"message_type\": \"normal\",\n  \"actor_type\": \"bot\"\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        4912,
        1600
      ],
      "id": "a51655ec-a28c-4cbf-8dbd-f78e02cd30b2",
      "name": "Send Requested Info Confirmation to Customer"
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "list",
          "cachedResultName": "Customer Service AI System",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit"
        },
        "sheetName": {
          "__rl": true,
          "value": 128263397,
          "mode": "list",
          "cachedResultName": "Issue Drafts",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit#gid=YOUR_SHEET_GID"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "issue_id": "={{ $('Classify Related Resolution Reply').item.json.issue_id }}",
            "updated_at": "={{ $now.setZone('Asia/Riyadh').toFormat('yyyy-MM-dd HH:mm:ss') }}",
            "status": "=pending",
            "is_active": "={{ true }}"
          },
          "matchingColumns": [
            "issue_id"
          ],
          "schema": [
            {
              "id": "issue_id",
              "displayName": "issue_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "conversation_id",
              "displayName": "conversation_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "conversation_internal_id",
              "displayName": "conversation_internal_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "customer_phone",
              "displayName": "customer_phone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "order_number",
              "displayName": "order_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "order_phone",
              "displayName": "order_phone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "issue_description",
              "displayName": "issue_description",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "image_urls",
              "displayName": "image_urls",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "status",
              "displayName": "status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "is_active",
              "displayName": "is_active",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "ticket_id",
              "displayName": "ticket_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "updated_at",
              "displayName": "updated_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "ticket_type\n",
              "displayName": "ticket_type\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_1\n",
              "displayName": "level_1\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_2\n",
              "displayName": "level_2\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_3\n",
              "displayName": "level_3\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "department_resolution",
              "displayName": "department_resolution",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "resolution_message_sent",
              "displayName": "resolution_message_sent",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "is_final_resolution",
              "displayName": "is_final_resolution",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "row_number",
              "displayName": "row_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "readOnly": true,
              "removed": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        5136,
        1600
      ],
      "id": "c684cf4e-c999-4479-8db8-44fb4d7874da",
      "name": "Set Issue Pending After Requested Info",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-5-mini",
          "mode": "list",
          "cachedResultName": "gpt-5-mini"
        },
        "responsesApiEnabled": false,
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        3824,
        3104
      ],
      "id": "20dcf807-8efc-422e-a2ad-265ad3d23d9a",
      "name": "OpenAI Chat Model5",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=\u0631\u0633\u0627\u0644\u0629 \u0627\u0644\u0639\u0645\u064a\u0644 \u0627\u0644\u062d\u0627\u0644\u064a\u0629:\n{{ $('Prepare Agent Input').item.json.agent_input }}\n\n\u0627\u0644\u0645\u0634\u0643\u0644\u0629 \u0623\u0648 \u0627\u0644\u0637\u0644\u0628 \u0627\u0644\u0623\u0635\u0644\u064a:\n{{ $json.issue_description }}\n\n\u0642\u0631\u0627\u0631 \u0627\u0644\u0642\u0633\u0645 \u0627\u0644\u0645\u062e\u062a\u0635:\n{{ $json.department_resolution }}\n\n\u0622\u062e\u0631 \u0631\u0633\u0627\u0644\u0629 \u0623\u0631\u0633\u0644\u0646\u0627\u0647\u0627 \u0644\u0644\u0639\u0645\u064a\u0644 \u0628\u062e\u0635\u0648\u0635 \u0627\u0644\u062d\u0644:\n{{ $json.resolution_message_sent }}",
        "hasOutputParser": true,
        "messages": {
          "messageValues": [
            {
              "message": "=You are a strict message splitter for Demo Laundry Customer Service.\n\nYour ONLY task is to split the customer's CURRENT mixed message into exactly two parts:\n\n1. related_part\nThe part that is related to the active issue, the approved resolution, or the last resolution message sent to the customer.\n\n2. unrelated_part\nThe part that is a separate new topic or general Demo Laundry question unrelated to the active issue/resolution.\n\nUse the full context provided:\n- customer's current message\n- original issue/request\n- department resolution\n- last resolution message sent to the customer\n\nIMPORTANT RULES:\n\n1. Do NOT answer the customer.\n2. Do NOT summarize.\n3. Do NOT rewrite the customer's meaning.\n4. Do NOT add information.\n5. Do NOT remove important details.\n6. Preserve the customer's wording as much as possible.\n7. Split only based on meaning and context.\n8. related_part must contain ONLY the portion related to the active resolution/issue.\n9. unrelated_part must contain ONLY the separate new topic.\n10. Never place the same information in both fields.\n11. Both fields must contain meaningful text because this node is used only after the message has already been classified as mixed.\n\nExamples:\n\nCurrent message:\n\"\u062a\u0645\u0627\u0645 \u0627\u0644\u062a\u0639\u0648\u064a\u0636 \u0645\u0646\u0627\u0633\u0628\u060c \u0648\u0628\u0627\u0644\u0645\u0646\u0627\u0633\u0628\u0629 \u0643\u0645 \u0633\u0639\u0631 \u0634\u0646\u0637\u0629 \u0643\u0644\u064a\u0646\u061f\"\n\nOutput meaning:\nrelated_part:\n\"\u062a\u0645\u0627\u0645 \u0627\u0644\u062a\u0639\u0648\u064a\u0636 \u0645\u0646\u0627\u0633\u0628\"\n\nunrelated_part:\n\"\u0643\u0645 \u0633\u0639\u0631 \u0634\u0646\u0637\u0629 \u0643\u0644\u064a\u0646\u061f\"\n\n\nCurrent message:\n\"\u0644\u0627 \u0627\u0644\u062a\u0639\u0648\u064a\u0636 \u0642\u0644\u064a\u0644 \u0648\u0623\u0628\u063a\u0649 \u062a\u0631\u0627\u062c\u0639\u0648\u0646\u0647\u060c \u0648\u0628\u0631\u0636\u0648 \u0643\u0645 \u0633\u0639\u0631 \u0628\u0627\u0642\u0629 299\u061f\"\n\nOutput meaning:\nrelated_part:\n\"\u0644\u0627 \u0627\u0644\u062a\u0639\u0648\u064a\u0636 \u0642\u0644\u064a\u0644 \u0648\u0623\u0628\u063a\u0649 \u062a\u0631\u0627\u062c\u0639\u0648\u0646\u0647\"\n\nunrelated_part:\n\"\u0643\u0645 \u0633\u0639\u0631 \u0628\u0627\u0642\u0629 299\u061f\"\n\n\nCurrent message:\n\"\u0628\u0643\u0631\u0629 \u0627\u0644\u0633\u0627\u0639\u0629 5 \u0645\u0646\u0627\u0633\u0628\u060c \u0648\u0639\u0646\u062f\u064a \u0633\u0624\u0627\u0644 \u062b\u0627\u0646\u064a \u0648\u064a\u0646 \u0623\u0642\u0631\u0628 \u0641\u0631\u0639\u061f\"\n\nIf the previous resolution asked the customer for a suitable time:\n\nOutput meaning:\nrelated_part:\n\"\u0628\u0643\u0631\u0629 \u0627\u0644\u0633\u0627\u0639\u0629 5 \u0645\u0646\u0627\u0633\u0628\"\n\nunrelated_part:\n\"\u0648\u064a\u0646 \u0623\u0642\u0631\u0628 \u0641\u0631\u0639\u061f\"\n\n\nCurrent message:\n\"\u0645\u062a\u0649 \u064a\u0646\u0632\u0644 \u0627\u0644\u062a\u0639\u0648\u064a\u0636\u061f \u0648\u0628\u0631\u0636\u0648 \u0643\u064a\u0641 \u0623\u0637\u0644\u0628 \u0634\u0646\u0637\u0629\u061f\"\n\nOutput meaning:\nrelated_part:\n\"\u0645\u062a\u0649 \u064a\u0646\u0632\u0644 \u0627\u0644\u062a\u0639\u0648\u064a\u0636\u061f\"\n\nunrelated_part:\n\"\u0643\u064a\u0641 \u0623\u0637\u0644\u0628 \u0634\u0646\u0637\u0629\u061f\"\n\nReturn only the structured output required by the connected output parser."
            }
          ]
        },
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.9,
      "position": [
        -336,
        2368
      ],
      "id": "bbce9508-5078-48dd-a006-5f1eabbeaaad",
      "name": "Split Mixed Customer Message"
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-5-nano",
          "mode": "list",
          "cachedResultName": "gpt-5-nano"
        },
        "responsesApiEnabled": false,
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        -336,
        2576
      ],
      "id": "ef42db58-e876-4281-b926-c3843082ba9c",
      "name": "OpenAI Chat Model6",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsonSchemaExample": "{\n  \"related_part\": \"\u0627\u0644\u062a\u0639\u0648\u064a\u0636 \u0645\u0646\u0627\u0633\u0628\",\n  \"unrelated_part\": \"\u0643\u0645 \u0633\u0639\u0631 \u0634\u0646\u0637\u0629 \u0643\u0644\u064a\u0646\u061f\"\n}"
      },
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "typeVersion": 1.3,
      "position": [
        -192,
        2576
      ],
      "id": "5e6e98f6-c659-4075-87b2-68f703ce0fc4",
      "name": "Structured Output Parser2"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "b2956099-b9af-4df6-bb38-5762a2df4fe1",
              "name": "current_message",
              "value": "={{ $json.output.related_part }}",
              "type": "string"
            },
            {
              "id": "5bae5c3b-3800-49b9-aa33-a8e076194fc4",
              "name": "issue_id ",
              "value": "={{ $('Classify Customer Reply to Resolution').item.json.issue_id }}",
              "type": "string"
            },
            {
              "id": "be6ddba6-9fcc-4d07-bbeb-383ba537bba0",
              "name": "ticket_id ",
              "value": "={{ $('Classify Customer Reply to Resolution').item.json.ticket_id }}",
              "type": "string"
            },
            {
              "id": "cfb765f4-813a-4a67-9f44-0149b280ffd1",
              "name": "issue_description ",
              "value": "={{ $('Classify Customer Reply to Resolution').item.json.issue_description }}",
              "type": "string"
            },
            {
              "id": "ca2bc904-30e9-4ec7-9c14-1d88c6974f42",
              "name": "department_resolution ",
              "value": "={{ $('Classify Customer Reply to Resolution').item.json.department_resolution }}",
              "type": "string"
            },
            {
              "id": "02121e8e-0a80-4e28-810c-a1011a1c5059",
              "name": "resolution_message_sent ",
              "value": "={{ $('Classify Customer Reply to Resolution').item.json.resolution_message_sent }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        256,
        2512
      ],
      "id": "a87aa115-9a34-419c-ab10-d3b8a9a07a59",
      "name": "Prepare Mixed Related Part"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "b2956099-b9af-4df6-bb38-5762a2df4fe1",
              "name": "current_message",
              "value": "={{ $json.output.unrelated_part }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        256,
        2272
      ],
      "id": "0c312d8e-bf1b-457a-b062-864b2c80fedb",
      "name": "Prepare Mixed Unrelated Part"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=\u0631\u0633\u0627\u0644\u0629 \u0627\u0644\u0639\u0645\u064a\u0644 \u0627\u0644\u062d\u0627\u0644\u064a\u0629:\n{{ $json.current_message || $('Prepare Agent Input').first().json.agent_input }}\n\n\u0627\u0644\u0645\u0634\u0643\u0644\u0629 \u0623\u0648 \u0627\u0644\u0637\u0644\u0628 \u0627\u0644\u0623\u0635\u0644\u064a:\n{{ $json.issue_description }}\n\n\u0642\u0631\u0627\u0631 \u0627\u0644\u0642\u0633\u0645 \u0627\u0644\u0645\u062e\u062a\u0635:\n{{ $json.department_resolution }}\n\n\u0622\u062e\u0631 \u0631\u0633\u0627\u0644\u0629 \u0623\u0631\u0633\u0644\u0646\u0627\u0647\u0627 \u0644\u0644\u0639\u0645\u064a\u0644 \u0628\u062e\u0635\u0648\u0635 \u0627\u0644\u062d\u0644:\n{{ $json.resolution_message_sent }}",
        "messages": {
          "messageValues": [
            {
              "message": "=You are a Demo Laundry Customer Service assistant responsible ONLY for answering customer questions about an already approved resolution.\n\nYou will receive:\n- the customer's current message\n- the original issue/request\n- the approved department resolution\n- the last resolution message sent to the customer\n\nYour job is to answer the customer's question clearly and naturally using ONLY:\n1. the approved resolution context\n2. the approved Demo Laundry information written below\n\nDo NOT create a new resolution.\nDo NOT change the approved resolution.\nDo NOT increase compensation.\nDo NOT approve a different solution.\nDo NOT invent dates, amounts, timings, procedures, or promises.\n\nThe message reaching you has already been classified as a question about the approved resolution.\n\n==================================================\nAPPROVED INFORMATION\n==================================================\n\n### Refunded / compensation balance\n\n- The customer can find the refunded balance inside the Demo Laundry application:\n  From the bottom navigation bar, choose \"\u0646\u0642\u0627\u0637\u064a\", then check \"\u0627\u0644\u0631\u0635\u064a\u062f \u0627\u0644\u0645\u0633\u062a\u0631\u062f\".\n\n- Gift balance and loyalty points are valid for 90 days.\n\n- After compensation balance is raised, it may take up to 24 hours to appear.\n\n- If the refunded balance does not appear:\n  Tell the customer to check \"\u0646\u0642\u0627\u0637\u064a\" and \"\u0627\u0644\u0631\u0635\u064a\u062f \u0627\u0644\u0645\u0633\u062a\u0631\u062f\" in the application.\n  The customer may also review previous orders because the balance may have already been used without noticing.\n\n- Refunded/compensation balance cannot be withdrawn as cash or transferred to a bank account.\n\n- The balance is linked to the customer's account.\n\n- Any unused remaining balance stays in the customer's account.\n\n- Only ONE discount method can be used on the same order.\n  The customer cannot combine refunded balance with another discount method such as a promo code on the same order.\n\n- The minimum Demo Laundry order is 29 SAR.\n\n- If the customer asks why the compensation amount was set at a certain value, reply politely with this meaning:\n  \"\u0627\u0644\u0639\u0641\u0648 \u0645\u0646\u0643 \u0639\u0632\u064a\u0632\u064a\u060c \u0627\u0644\u062a\u0639\u0648\u064a\u0636 \u064a\u062a\u0645 \u0648\u0641\u0642 \u0627\u0644\u0633\u064a\u0627\u0633\u0629 \u0627\u0644\u0645\u0648\u0627\u0641\u0642 \u0639\u0644\u064a\u0647\u0627 \u0639\u0646\u062f \u0625\u0646\u0634\u0627\u0621 \u0627\u0644\u0637\u0644\u0628\u060c \u0648\u062a\u0642\u062f\u0631 \u062a\u062a\u0623\u0643\u062f \u0645\u0646 \u062e\u0644\u0627\u0644 \u0627\u0644\u0625\u0639\u062f\u0627\u062f\u0627\u062a > \u0627\u0644\u0634\u0631\u0648\u0637 \u0648\u0627\u0644\u0623\u062d\u0643\u0627\u0645\u060c \u0623\u0648 \u0645\u0646 \u0627\u0644\u0634\u0631\u0648\u0637 \u0648\u0627\u0644\u0623\u062d\u0643\u0627\u0645 \u0627\u0644\u0638\u0627\u0647\u0631\u0629 \u0642\u0628\u0644 \u0625\u0643\u0645\u0627\u0644 \u0627\u0644\u0637\u0644\u0628.\"\n\nDo not independently explain how compensation amounts are calculated beyond this approved answer.\n\n==================================================\nRE-SERVICE\n==================================================\n\n- Whether re-service is approved and its exact conditions depend on the resolution approved by the responsible team.\n\n- If the approved resolution is re-service for an online order, pickup and delivery for the approved re-service are without additional delivery charges.\n\n- For washing and ironing re-service, the expected service duration after receiving the item is approximately 24 hours.\n\n- For damage-related cases, the duration depends on the type of damage and is generally around 48 hours when applicable.\n\n- When re-service requires arranging pickup, the customer must choose ONE of these available time windows:\n\n  1. 11:00 AM to 3:00 PM\n  2. 4:00 PM to 7:00 PM\n  3. 8:00 PM to 10:00 PM\n\n- The customer has 3 days to select the appropriate re-service pickup period.\n\n- The item must not be used during this period before the re-service process.\n\n- Do not allow the customer to invent an arbitrary pickup time outside the approved periods.\n\n- If a pickup period has already been confirmed, the appropriate confirmation is:\n  \"\u062a\u0645 \u062a\u0623\u0643\u064a\u062f \u0627\u0644\u0645\u0648\u0639\u062f.\"\n\n- If the driver does not arrive during the confirmed period, the pickup should take place during the nearest available following period.\n\n\n==================================================\nRE-SERVICE APPOINTMENT RULES\n==================================================\n\nWhen answering questions about re-service:\n\n1. Answer ONLY what the customer asked.\nDo not proactively ask the customer to schedule a pickup unless choosing a pickup period is actually required at this stage.\n\nExample:\n\nCustomer:\n\"\u0643\u0645 \u062a\u0633\u062a\u063a\u0631\u0642 \u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u062e\u062f\u0645\u0629\u061f\"\n\nCorrect:\n\"\u0639\u0627\u062f\u0629\u064b \u0625\u0639\u0627\u062f\u0629 \u062e\u062f\u0645\u0629 \u0627\u0644\u063a\u0633\u064a\u0644 \u0648\u0627\u0644\u0643\u0648\u064a \u062a\u0633\u062a\u063a\u0631\u0642 \u062d\u0648\u0627\u0644\u064a 24 \u0633\u0627\u0639\u0629 \u0645\u0646 \u0648\u0642\u062a \u0627\u0633\u062a\u0644\u0627\u0645 \u0627\u0644\u0642\u0637\u0639\u0629.\"\n\nDo NOT add:\n\"\u0645\u062a\u0649 \u0627\u0644\u0648\u0642\u062a \u0627\u0644\u0645\u0646\u0627\u0633\u0628 \u0644\u0643\u061f\"\nor any scheduling question unless scheduling is required.\n\n2. If the customer needs to choose a pickup time for an approved re-service, NEVER ask an open-ended question such as:\n- \"\u0645\u062a\u0649 \u0627\u0644\u0648\u0642\u062a \u0627\u0644\u0645\u0646\u0627\u0633\u0628 \u0644\u0643\u061f\"\n- \"\u062d\u062f\u062f \u0627\u0644\u0648\u0642\u062a \u0627\u0644\u0644\u064a \u064a\u0646\u0627\u0633\u0628\u0643\"\n- \"\u0623\u064a \u0633\u0627\u0639\u0629 \u062a\u0646\u0627\u0633\u0628\u0643\u061f\"\n\nThe customer may ONLY choose one of these approved pickup periods:\n\n- \u0645\u0646 11:00 \u0635\u0628\u0627\u062d\u064b\u0627 \u0625\u0644\u0649 3:00 \u0639\u0635\u0631\u064b\u0627\n- \u0645\u0646 4:00 \u0639\u0635\u0631\u064b\u0627 \u0625\u0644\u0649 7:00 \u0645\u0633\u0627\u0621\u064b\n- \u0645\u0646 8:00 \u0645\u0633\u0627\u0621\u064b \u0625\u0644\u0649 10:00 \u0645\u0633\u0627\u0621\u064b\n\n3. When asking the customer to choose a pickup period, clearly present the available periods and ask them to choose one.\n\nExample:\n\"\u0627\u062e\u062a\u0631 \u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u0645\u0646\u0627\u0633\u0628\u0629 \u0644\u0643 \u0644\u0644\u0627\u0633\u062a\u0644\u0627\u0645 \ud83d\ude4f\n\u0645\u0646 11 \u0635 \u0625\u0644\u0649 3 \u0645\u060c \u0623\u0648 \u0645\u0646 4 \u0645 \u0625\u0644\u0649 7 \u0645\u060c \u0623\u0648 \u0645\u0646 8 \u0645 \u0625\u0644\u0649 10 \u0645.\"\n\n4. Never invent, suggest, accept, or offer a pickup period outside these approved periods.\n\n5. The customer has up to 3 days to select the appropriate pickup period for the approved re-service.\n\n6. The item must not be used before the approved re-service is completed.\n\n7. If the customer asks only an informational question, answer that question directly without adding unnecessary next steps.\n\n8. IMPORTANT FORMATTING RULE FOR PICKUP PERIODS:\n\nWhenever you mention two or more approved pickup periods to the customer, ALWAYS display them as a clear vertical list.\n\nNEVER write multiple pickup periods in one sentence or on the same line.\n\nUse exactly this style:\n\n\"\u0627\u0644\u0641\u062a\u0631\u0627\u062a \u0627\u0644\u0645\u062a\u0627\u062d\u0629 \u0644\u0644\u0627\u0633\u062a\u0644\u0627\u0645 \u0647\u064a:\n\u2022 \u0645\u0646 11:00 \u0635\u0628\u0627\u062d\u064b\u0627 \u0625\u0644\u0649 3:00 \u0639\u0635\u0631\u064b\u0627\n\u2022 \u0645\u0646 4:00 \u0639\u0635\u0631\u064b\u0627 \u0625\u0644\u0649 7:00 \u0645\u0633\u0627\u0621\u064b\n\u2022 \u0645\u0646 8:00 \u0645\u0633\u0627\u0621\u064b \u0625\u0644\u0649 10:00 \u0645\u0633\u0627\u0621\u064b\"\n\nIf the customer needs to choose one, use:\n\n\"\u0627\u062e\u062a\u0631 \u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u0645\u0646\u0627\u0633\u0628\u0629 \u0644\u0643 \u0644\u0644\u0627\u0633\u062a\u0644\u0627\u0645 \ud83d\ude4f\n\u2022 \u0645\u0646 11:00 \u0635\u0628\u0627\u062d\u064b\u0627 \u0625\u0644\u0649 3:00 \u0639\u0635\u0631\u064b\u0627\n\u2022 \u0645\u0646 4:00 \u0639\u0635\u0631\u064b\u0627 \u0625\u0644\u0649 7:00 \u0645\u0633\u0627\u0621\u064b\n\u2022 \u0645\u0646 8:00 \u0645\u0633\u0627\u0621\u064b \u0625\u0644\u0649 10:00 \u0645\u0633\u0627\u0621\u064b\"\n\nEach period MUST be on its own separate line.\n\nDo NOT format the periods like:\n\"\u0645\u0646 11 \u0625\u0644\u0649 3\u060c \u0623\u0648 \u0645\u0646 4 \u0625\u0644\u0649 7\u060c \u0623\u0648 \u0645\u0646 8 \u0625\u0644\u0649 10.\"\n\nDo NOT combine the periods into a paragraph.\n\nIf only ONE specific period is relevant, you may mention that single period normally without a bullet list.\n\n==================================================\nBANK / CARD REFUNDS\n==================================================\n\nCompensation may also be approved as:\n- bank transfer\n- refund to the original payment card\n\nApproved expected timelines:\n\n- Bank transfer: approximately 2 weeks\n- Mada refund: approximately 48 hours\n- Visa refund: approximately 14 days\n\nOnly mention the method that is relevant to the customer's approved resolution.\n\n==================================================\nGENERAL RESOLUTION TIMING\n==================================================\n\nEach issue has its own procedure.\n\nIn general, the responsible team may provide the appropriate resolution within approximately 1 to 3 hours.\n\nSome ironing-related cases may receive a re-service resolution within approximately 30 minutes.\n\nDo NOT promise these times if the customer is asking about an already delayed specific case unless the context clearly supports it.\n\n==================================================\nCUSTOMER RESPONSE STYLE\n==================================================\n\nReply in natural, polite Saudi Arabic.\n\nKeep the answer:\n\n- short\n- clear\n- conversational\n- directly related to the customer's question\n- normally 1 or 2 sentences\n\nEXCEPTION:\nWhen presenting multiple pickup periods or multiple selectable options, prioritize readability over the 1\u20132 sentence rule.\nDisplay each option on a separate line using bullet points.\n\nDo not mention internal terms such as:\n- ticket\n- workflow\n- classifier\n- department note\n- status\n- internal process\n\nDo not tell the customer unnecessary internal operational details.\n\nIf the answer is explicitly available in the approved information above or in the approved resolution, answer it directly.\n\nNever make up missing information."
            }
          ]
        },
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.9,
      "position": [
        3760,
        2880
      ],
      "id": "f0616c6c-c053-4494-937d-e68f21eae17b",
      "name": "Answer Question About Resolution1"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://YOUR_FRESHCHAT_DOMAIN.freshchat.com/v2/conversations/{{ $('Normalize Freshchat Event').item.json.conversation_id }}/messages",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_API_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Accept",
              "value": "application/json"
            },
            {
              "name": "ASSUME-IDENTITY",
              "value": "false"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"message_parts\": [\n    {\n      \"text\": {\n        \"content\": {{ JSON.stringify($json.text) }}\n      }\n    }\n  ],\n  \"message_type\": \"normal\",\n  \"actor_type\": \"bot\"\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        4176,
        2976
      ],
      "id": "c31eba23-3b5e-4d76-a5e1-de80d475c54a",
      "name": "Answer Question About Resolution2"
    },
    {
      "parameters": {
        "inputText": "=\u0631\u0633\u0627\u0644\u0629 \u0627\u0644\u0639\u0645\u064a\u0644 \u0627\u0644\u062d\u0627\u0644\u064a\u0629:\n{{ $json.current_message || $('Prepare Agent Input').first().json.agent_input }}\n\n\u0627\u0644\u0635\u0648\u0631 \u0627\u0644\u0645\u0631\u0633\u0644\u0629 \u0641\u064a \u0627\u0644\u0631\u062f \u0627\u0644\u062d\u0627\u0644\u064a:\n{{\n(() => {\n  try {\n    const batch = $('Keep Latest Image Batch').first().json;\n    const images = Array.isArray(batch.image_urls)\n      ? batch.image_urls\n      : [];\n\n    return images.length > 0\n      ? `YES - \u062a\u0645 \u0627\u0633\u062a\u0644\u0627\u0645 ${images.length} \u0635\u0648\u0631\u0629 \u0641\u064a \u0627\u0644\u0631\u062f \u0627\u0644\u062d\u0627\u0644\u064a`\n      : 'NO - \u0644\u0627 \u062a\u0648\u062c\u062f \u0635\u0648\u0631 \u0641\u064a \u0627\u0644\u0631\u062f \u0627\u0644\u062d\u0627\u0644\u064a';\n  } catch (e) {\n    return 'NO - \u0644\u0627 \u062a\u0648\u062c\u062f \u0635\u0648\u0631 \u0641\u064a \u0627\u0644\u0631\u062f \u0627\u0644\u062d\u0627\u0644\u064a';\n  }\n})()\n}}\n\n\u0627\u0644\u0645\u0634\u0643\u0644\u0629 \u0623\u0648 \u0627\u0644\u0637\u0644\u0628 \u0627\u0644\u0623\u0635\u0644\u064a:\n{{ $json.issue_description || $json['issue_description '] }}\n\n\u0642\u0631\u0627\u0631 \u0627\u0644\u0642\u0633\u0645 \u0627\u0644\u0645\u062e\u062a\u0635:\n{{ $json.department_resolution || $json['department_resolution '] }}\n\n\u0622\u062e\u0631 \u0631\u0633\u0627\u0644\u0629 \u0623\u0631\u0633\u0644\u0646\u0627\u0647\u0627 \u0644\u0644\u0639\u0645\u064a\u0644 \u0628\u062e\u0635\u0648\u0635 \u0627\u0644\u062d\u0644:\n{{ $json.resolution_message_sent || $json['resolution_message_sent '] }}",
        "categories": {
          "categories": [
            {
              "category": "valid_info",
              "description": "=CRITICAL IMAGE RULE:\n\nIf the previous resolution message asked the customer to send an image, photo, or visual evidence, and the current customer message indicates that one or more images were actually received, ALWAYS classify as valid_info.\n\nThe customer does NOT need to write any accompanying text.\n\nExamples:\n\nPrevious message:\n\"\u0641\u0636\u0644\u0627\u064b \u0623\u0631\u0633\u0644 \u0635\u0648\u0631\u0629 \u0648\u0627\u0636\u062d\u0629 \u0644\u0644\u0645\u0634\u0643\u0644\u0629\"\n\nCurrent message:\n\"[\u0627\u0644\u0639\u0645\u064a\u0644 \u0623\u0631\u0633\u0644 \u0635\u0648\u0631\u0629 \u0623\u0648 \u0623\u0643\u062b\u0631 \u0628\u062f\u0648\u0646 \u0646\u0635...]\"\n\u2192 valid_info\n\nPrevious message:\n\"\u064a\u0631\u062c\u0649 \u0625\u0631\u0633\u0627\u0644 \u0635\u0648\u0631\u0629 \u062a\u0648\u0636\u062d \u0627\u0644\u0628\u0642\u0639\u0629\"\n\nCurrent message:\n\"[\u0627\u0644\u0639\u0645\u064a\u0644 \u0623\u0631\u0633\u0644 \u0635\u0648\u0631\u0629 \u0623\u0648 \u0623\u0643\u062b\u0631...]\"\n\u2192 valid_info\n\nIf an image was actually received, do NOT classify it as invalid_or_incomplete_info merely because there is no text.\n\nChoose this category when the customer has provided or confirmed the requested information clearly enough to continue the approved resolution.\n\nFor re-service pickup periods, valid information includes:\n\n- explicitly choosing 11:00 AM to 3:00 PM\n- explicitly choosing 4:00 PM to 7:00 PM\n- explicitly choosing 8:00 PM to 10:00 PM\n- saying \"\u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u0623\u0648\u0644\u0649\", \"\u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u062b\u0627\u0646\u064a\u0629\", or \"\u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u062b\u0627\u0644\u062b\u0629\" when the previous message clearly listed those three periods\n- giving a specific time that clearly falls inside one approved period, such as:\n  - \"\u0627\u0644\u0633\u0627\u0639\u0629 12\" \u2192 valid for 11 AM to 3 PM\n  - \"\u0627\u0644\u0633\u0627\u0639\u0629 5\" \u2192 valid for 4 PM to 7 PM\n  - \"\u0627\u0644\u0633\u0627\u0639\u0629 9\" \u2192 valid for 8 PM to 10 PM\n- confirming a specific proposed period when the previous message already asked for confirmation, for example:\n\nPrevious message:\n\"\u0647\u0644 \u0646\u0639\u062a\u0645\u062f \u0644\u0643 \u0627\u0644\u0641\u062a\u0631\u0629 \u0645\u0646 4 \u0625\u0644\u0649 7 \u0645\u0633\u0627\u0621\u064b\u061f\"\n\nCustomer:\n\"\u062a\u0645\u0627\u0645 \u0627\u0639\u062a\u0645\u062f\u0648\u0647\u0627\"\n\u2192 valid_info\n\nFor other requested information such as an address or confirmation, choose valid_info when the customer clearly provided the information that was requested."
            },
            {
              "category": "invalid_or_incomplete_info",
              "description": "=IMPORTANT IMAGE RULE:\n\nDo NOT choose this category when the customer actually sent an image and the previous resolution requested an image.\n\nChoose invalid_or_incomplete_info for image requests only when the customer has NOT actually provided the requested image.\n\nExamples:\n\n\"\u0628\u0631\u0633\u0644 \u0627\u0644\u0635\u0648\u0631\u0629 \u0628\u0639\u062f\u064a\u0646\"\n\u2192 invalid_or_incomplete_info\n\n\"\u0645\u0627 \u0639\u0646\u062f\u064a \u0627\u0644\u0635\u0648\u0631\u0629 \u0627\u0644\u0622\u0646\"\n\u2192 invalid_or_incomplete_info\n\nActual image received with no text\n\u2192 valid_info\nChoose this category when the customer attempted to respond to the requested information but the answer is incomplete, ambiguous, or cannot be safely used to continue the approved resolution.\n\nFor re-service pickup periods, choose this category when:\n\n- the customer says \"\u0627\u0644\u0622\u0646\"\n- the customer gives a time outside the approved periods\n- the customer gives a time between approved periods, such as 3:30 PM or 7:30 PM\n- the customer asks for a period not offered\n- the customer says only \"\u062a\u0645\u0627\u0645\", \"\u0627\u0648\u0643\u064a\", \"\u0645\u0648\u0627\u0641\u0642\", or \"\u0627\u0639\u062a\u0645\u062f\u0648\u0647\u0627\" when no specific period was previously proposed for confirmation\n- the customer says \"\u0623\u064a \u0648\u0642\u062a\", \"\u0628\u0639\u062f \u0634\u0648\u064a\", \"\u0628\u0639\u062f\u064a\u0646\", or another vague time\n- the customer gives information that is not enough to determine the requested choice safely\n\nApproved re-service pickup periods are ONLY:\n\n1. 11:00 AM to 3:00 PM\n2. 4:00 PM to 7:00 PM\n3. 8:00 PM to 10:00 PM\n\nDo not assume a period if the customer's meaning is unclear.\n\nDo not automatically interpret \"\u0627\u0644\u0622\u0646\" as the current approved period.\n\nFor other requested information, choose this category when the information requested by Demo Laundry is still missing, unclear, or incomplete."
            }
          ]
        },
        "options": {
          "systemPromptTemplate": "=You are a strict validation classifier for Demo Laundry Customer Service.\n\nYour ONLY task is to determine whether the information provided by the customer is valid and sufficient to continue the already approved resolution.\n\nAvailable categories:\n{categories}\n\nUse the FULL context provided in the input:\n- the customer's current message\n- the original issue/request\n- the approved department resolution\n- the last resolution message sent to the customer\n\nDo NOT answer the customer.\nDo NOT rewrite the customer's message.\nDo NOT create a new resolution.\nDo NOT make promises.\nOnly classify the provided information into exactly ONE available category.\n\n==================================================\nGENERAL RULE\n==================================================\n\nThe customer has already been classified as providing or attempting to provide information requested for the active resolution.\n\nYour job now is ONLY to decide:\n\n- Is the information clear, complete, and safe to use?\nOR\n- Is it incomplete, ambiguous, invalid, or outside the allowed rules?\n\n==================================================\nVALID_INFO\n==================================================\n\nChoose \"valid_info\" when the customer clearly provides or confirms enough information to continue the approved resolution.\n\nFor re-service pickup scheduling, the ONLY approved pickup periods are:\n\n1. 11:00 AM to 3:00 PM\n2. 4:00 PM to 7:00 PM\n3. 8:00 PM to 10:00 PM\n\nValid examples include:\n\nCustomer:\n\"\u0645\u0646 11 \u0625\u0644\u0649 3\"\n\u2192 valid_info\n\nCustomer:\n\"\u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u0623\u0648\u0644\u0649\"\nwhen the previous message listed the three approved periods\n\u2192 valid_info\n\nCustomer:\n\"\u0645\u0646 4 \u0625\u0644\u0649 7\"\n\u2192 valid_info\n\nCustomer:\n\"\u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u062b\u0627\u0646\u064a\u0629\"\n\u2192 valid_info\n\nCustomer:\n\"\u0645\u0646 8 \u0625\u0644\u0649 10\"\n\u2192 valid_info\n\nCustomer:\n\"\u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u062b\u0627\u0644\u062b\u0629\"\n\u2192 valid_info\n\nA specific clock time is also valid ONLY when it clearly falls inside one approved pickup period.\n\nExamples:\n\n\"\u0627\u0644\u0633\u0627\u0639\u0629 12\"\n\u2192 valid_info\nbecause it falls within 11 AM\u20133 PM\n\n\"\u0627\u0644\u0633\u0627\u0639\u0629 2\"\n\u2192 valid_info\nbecause it falls within 11 AM\u20133 PM\n\n\"\u0627\u0644\u0633\u0627\u0639\u0629 5\"\n\u2192 valid_info\nbecause it falls within 4 PM\u20137 PM\n\n\"\u0627\u0644\u0633\u0627\u0639\u0629 6\"\n\u2192 valid_info\nbecause it falls within 4 PM\u20137 PM\n\n\"\u0627\u0644\u0633\u0627\u0639\u0629 9\"\n\u2192 valid_info\nbecause it falls within 8 PM\u201310 PM\n\nIf the previous message proposed ONE specific approved period and explicitly asked the customer to confirm it, a clear confirmation is valid.\n\nExample:\n\nPrevious message:\n\"\u0647\u0644 \u0646\u0639\u062a\u0645\u062f \u0644\u0643 \u0627\u0644\u0641\u062a\u0631\u0629 \u0645\u0646 4 \u0625\u0644\u0649 7 \u0645\u0633\u0627\u0621\u064b\u061f\"\n\nCustomer:\n\"\u062a\u0645\u0627\u0645 \u0627\u0639\u062a\u0645\u062f\u0648\u0647\u0627\"\n\u2192 valid_info\n\nCustomer:\n\"\u0646\u0639\u0645\"\n\u2192 valid_info\n\nFor other requested information, such as an address or another confirmation, choose valid_info when the customer clearly provides exactly what was requested.\n\n==================================================\nINVALID_OR_INCOMPLETE_INFO\n==================================================\n\nChoose \"invalid_or_incomplete_info\" whenever the information cannot safely be used to continue the resolution.\n\nFor re-service scheduling, choose this category when:\n\n- the customer says \"\u0627\u0644\u0622\u0646\"\n- the customer says \"\u062a\u0639\u0627\u0644\u0648\u0627 \u0627\u0644\u0622\u0646\"\n- the customer gives a time outside all approved pickup periods\n- the customer gives a time in the gap between approved periods\n- the customer gives a vague time\n- the customer has not clearly selected or confirmed a usable period\n- the meaning requires guessing\n\nExamples:\n\n\"\u0627\u0644\u0633\u0627\u0639\u0629 3:30\"\n\u2192 invalid_or_incomplete_info\nbecause it is between the 11\u20133 and 4\u20137 periods\n\n\"\u0627\u0644\u0633\u0627\u0639\u0629 7:30\"\n\u2192 invalid_or_incomplete_info\nbecause it is between the 4\u20137 and 8\u201310 periods\n\n\"\u0627\u0644\u0633\u0627\u0639\u0629 11 \u0628\u0627\u0644\u0644\u064a\u0644\"\n\u2192 invalid_or_incomplete_info\n\n\"\u0628\u0639\u062f \u0634\u0648\u064a\"\n\u2192 invalid_or_incomplete_info\n\n\"\u0623\u064a \u0648\u0642\u062a\"\n\u2192 invalid_or_incomplete_info\n\n\"\u0628\u0639\u062f\u064a\u0646\"\n\u2192 invalid_or_incomplete_info\n\n\"\u0627\u0644\u0622\u0646\"\n\u2192 invalid_or_incomplete_info\n\nIMPORTANT:\nNever automatically convert \"\u0627\u0644\u0622\u0646\" into the currently active pickup period, even if the current time happens to fall inside an approved period.\n\nIf the customer only says:\n\n\"\u062a\u0645\u0627\u0645\"\n\"\u0627\u0648\u0643\u064a\"\n\"\u0645\u0648\u0627\u0641\u0642\"\n\"\u0627\u0639\u062a\u0645\u062f\u0648\u0647\u0627\"\n\nand the previous message did NOT propose one specific period for confirmation, choose:\ninvalid_or_incomplete_info\n\nDo not guess which period the customer meant.\n\n==================================================\nOTHER REQUESTED INFORMATION\n==================================================\n\nThis validator is not only for pickup times.\n\nIf the previous resolution requested another type of information, such as:\n- confirming an address\n- confirming a specific detail\n- providing another required piece of information\n\nthen evaluate whether the customer's response clearly provides what was requested.\n\nIf complete and clear:\n\u2192 valid_info\n\nIf missing, unclear, ambiguous, or insufficient:\n\u2192 invalid_or_incomplete_info\n\n==================================================\nFINAL RULES\n==================================================\n\nNever infer information that the customer did not provide.\n\nNever choose a pickup period on behalf of the customer.\n\nNever change an invalid time into another period automatically.\n\nNever answer the customer.\n\nReturn exactly ONE classification from the available categories."
        }
      },
      "type": "@n8n/n8n-nodes-langchain.textClassifier",
      "typeVersion": 1.1,
      "position": [
        3760,
        1792
      ],
      "id": "ab970a81-e344-4cc8-91e2-ea45dcdbde34",
      "name": "Validate Requested Resolution Info"
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-5-nano",
          "mode": "list",
          "cachedResultName": "gpt-5-nano"
        },
        "responsesApiEnabled": false,
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        3824,
        2016
      ],
      "id": "96a3f1f0-4ffc-47f7-b7e9-582e8c026835",
      "name": "OpenAI Chat Model7",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://YOUR_FRESHCHAT_DOMAIN.freshchat.com/v2/conversations/{{ $('Normalize Freshchat Event').item.json.conversation_id }}/messages",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_API_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Accept",
              "value": "application/json"
            },
            {
              "name": "ASSUME-IDENTITY",
              "value": "false"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"message_parts\": [\n    {\n      \"text\": {\n        \"content\": {{ JSON.stringify($json.text) }}\n      }\n    }\n  ],\n  \"message_type\": \"normal\",\n  \"actor_type\": \"bot\"\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        4464,
        2000
      ],
      "id": "3de806e1-e1e5-4b86-864d-8496bd6bb699",
      "name": "Send Available Pickup Periods to Customer"
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "list",
          "cachedResultName": "Customer Service AI System",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit"
        },
        "sheetName": {
          "__rl": true,
          "value": 128263397,
          "mode": "list",
          "cachedResultName": "Issue Drafts",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit#gid=YOUR_SHEET_GID"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "issue_id": "={{ $('Classify Related Resolution Reply').item.json.issue_id }}",
            "updated_at": "={{ $now.setZone('Asia/Riyadh').toFormat('yyyy-MM-dd HH:mm:ss') }}",
            "is_active": "={{ true }}",
            "resolution_message_sent": "={{ $('Generate Requested Info Clarification').item.json.text }}"
          },
          "matchingColumns": [
            "issue_id"
          ],
          "schema": [
            {
              "id": "issue_id",
              "displayName": "issue_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "conversation_id",
              "displayName": "conversation_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "conversation_internal_id",
              "displayName": "conversation_internal_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "customer_phone",
              "displayName": "customer_phone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "order_number",
              "displayName": "order_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "order_phone",
              "displayName": "order_phone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "issue_description",
              "displayName": "issue_description",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "image_urls",
              "displayName": "image_urls",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "status",
              "displayName": "status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "is_active",
              "displayName": "is_active",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "ticket_id",
              "displayName": "ticket_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "updated_at",
              "displayName": "updated_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "ticket_type\n",
              "displayName": "ticket_type\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_1\n",
              "displayName": "level_1\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_2\n",
              "displayName": "level_2\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_3\n",
              "displayName": "level_3\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "department_resolution",
              "displayName": "department_resolution",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "resolution_message_sent",
              "displayName": "resolution_message_sent",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "is_final_resolution",
              "displayName": "is_final_resolution",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "row_number",
              "displayName": "row_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "readOnly": true,
              "removed": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        4688,
        2000
      ],
      "id": "1d34e338-e402-4aa1-b0fa-30a46da2ed6b",
      "name": "Update Last Resolution Message After Invalid Info",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-5-mini",
          "mode": "list",
          "cachedResultName": "gpt-5-mini"
        },
        "responsesApiEnabled": false,
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        4176,
        1712
      ],
      "id": "a5942811-dd08-4d0e-b707-b591eb425ef3",
      "name": "OpenAI Chat Model8",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=\u0631\u0633\u0627\u0644\u0629 \u0627\u0644\u0639\u0645\u064a\u0644 \u0627\u0644\u062d\u0627\u0644\u064a\u0629:\n{{ $json.current_message || $('Prepare Agent Input').first().json.agent_input }}\n\n\u0622\u062e\u0631 \u0631\u0633\u0627\u0644\u0629 \u0623\u0631\u0633\u0644\u0646\u0627\u0647\u0627 \u0644\u0644\u0639\u0645\u064a\u0644 \u0628\u062e\u0635\u0648\u0635 \u0627\u0644\u062d\u0644:\n{{ $json.resolution_message_sent }}",
        "messages": {
          "messageValues": [
            {
              "message": "=IMAGE RESPONSE RULE:\n\nIf the customer actually sent one or more requested images, keep the internal note very short.\n\nReturn:\n\"\u0627\u0644\u0639\u0645\u064a\u0644 \u0623\u0631\u0633\u0644 \u0627\u0644\u0635\u0648\u0631\u0629 \u0627\u0644\u0645\u0637\u0644\u0648\u0628\u0629 \u0644\u0627\u0633\u062a\u0643\u0645\u0627\u0644 \u0627\u0644\u0625\u062c\u0631\u0627\u0621.\"\n\nIf multiple images were received, return:\n\"\u0627\u0644\u0639\u0645\u064a\u0644 \u0623\u0631\u0633\u0644 \u0627\u0644\u0635\u0648\u0631 \u0627\u0644\u0645\u0637\u0644\u0648\u0628\u0629 \u0644\u0627\u0633\u062a\u0643\u0645\u0627\u0644 \u0627\u0644\u0625\u062c\u0631\u0627\u0621.\"\n\nDo not explain the image content.\nDo not repeat the original issue.\nDo not mention that the image was validated.\n\nYou are an internal information normalizer for Demo Laundry Customer Service.\n\nYour ONLY task is to convert the customer's valid requested information into a clear operational note for the responsible team.\n\nThe output is INTERNAL and will be added as a private note to the Freshdesk ticket.\n\nDo NOT answer the customer.\nDo NOT add greetings.\nDo NOT invent information.\nDo NOT change the customer's intended choice.\nDo NOT create or approve a new resolution.\n\n==================================================\nRE-SERVICE PICKUP PERIODS\n==================================================\n\nThe ONLY approved pickup periods are:\n\n1. 11:00 AM to 3:00 PM\n2. 4:00 PM to 7:00 PM\n3. 8:00 PM to 10:00 PM\n\nThe customer's information has already been validated before reaching you.\n\nYour job is to normalize it for the responsible team.\n\n==================================================\nIF THE CUSTOMER PROVIDED A SPECIFIC TIME\n==================================================\n\nIf the customer gave a specific clock time that falls inside an approved period:\n\n- preserve the exact time the customer selected\n- also state the approved pickup period that contains that time\n- NEVER describe the exact time as the confirmed driver arrival time\n- make it clear that the exact time is the customer's selection and that it falls within the approved service period\n\nExamples:\n\nCustomer:\n\"\u0627\u0644\u0633\u0627\u0639\u0629 5\"\n\nOutput:\n\u0627\u062e\u062a\u064a\u0627\u0631 \u0627\u0644\u0639\u0645\u064a\u0644 \u0644\u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u062e\u062f\u0645\u0629: \u0627\u0644\u0639\u0645\u064a\u0644 \u0627\u062e\u062a\u0627\u0631 \u0627\u0644\u0633\u0627\u0639\u0629 5:00 \u0645\u0633\u0627\u0621\u064b\u060c \u0648\u0647\u064a \u0636\u0645\u0646 \u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u0645\u0639\u062a\u0645\u062f\u0629 \u0645\u0646 4:00 \u0639\u0635\u0631\u064b\u0627 \u0625\u0644\u0649 7:00 \u0645\u0633\u0627\u0621\u064b.\n\nCustomer:\n\"\u0627\u0644\u0633\u0627\u0639\u0629 1\"\n\nOutput:\n\u0627\u062e\u062a\u064a\u0627\u0631 \u0627\u0644\u0639\u0645\u064a\u0644 \u0644\u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u062e\u062f\u0645\u0629: \u0627\u0644\u0639\u0645\u064a\u0644 \u0627\u062e\u062a\u0627\u0631 \u0627\u0644\u0633\u0627\u0639\u0629 1:00 \u0638\u0647\u0631\u064b\u0627\u060c \u0648\u0647\u064a \u0636\u0645\u0646 \u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u0645\u0639\u062a\u0645\u062f\u0629 \u0645\u0646 11:00 \u0635\u0628\u0627\u062d\u064b\u0627 \u0625\u0644\u0649 3:00 \u0639\u0635\u0631\u064b\u0627.\n\nCustomer:\n\"\u0627\u0644\u0633\u0627\u0639\u0629 9\"\n\nOutput:\n\u0627\u062e\u062a\u064a\u0627\u0631 \u0627\u0644\u0639\u0645\u064a\u0644 \u0644\u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u062e\u062f\u0645\u0629: \u0627\u0644\u0639\u0645\u064a\u0644 \u0627\u062e\u062a\u0627\u0631 \u0627\u0644\u0633\u0627\u0639\u0629 9:00 \u0645\u0633\u0627\u0621\u064b\u060c \u0648\u0647\u064a \u0636\u0645\u0646 \u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u0645\u0639\u062a\u0645\u062f\u0629 \u0645\u0646 8:00 \u0645\u0633\u0627\u0621\u064b \u0625\u0644\u0649 10:00 \u0645\u0633\u0627\u0621\u064b.\n\n==================================================\nIF THE CUSTOMER SELECTED A PERIOD\n==================================================\n\nIf the customer selected an approved period directly, normalize it to the full official period.\n\nExamples:\n\nCustomer:\n\"\u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u0623\u0648\u0644\u0649\"\n\nOutput:\n\u0627\u062e\u062a\u064a\u0627\u0631 \u0627\u0644\u0639\u0645\u064a\u0644 \u0644\u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u062e\u062f\u0645\u0629: \u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u0645\u0639\u062a\u0645\u062f\u0629 \u0645\u0646 11:00 \u0635\u0628\u0627\u062d\u064b\u0627 \u0625\u0644\u0649 3:00 \u0639\u0635\u0631\u064b\u0627.\n\nCustomer:\n\"\u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u062b\u0627\u0646\u064a\u0629\"\n\nOutput:\n\u0627\u062e\u062a\u064a\u0627\u0631 \u0627\u0644\u0639\u0645\u064a\u0644 \u0644\u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u062e\u062f\u0645\u0629: \u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u0645\u0639\u062a\u0645\u062f\u0629 \u0645\u0646 4:00 \u0639\u0635\u0631\u064b\u0627 \u0625\u0644\u0649 7:00 \u0645\u0633\u0627\u0621\u064b.\n\nCustomer:\n\"\u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u062b\u0627\u0644\u062b\u0629\"\n\nOutput:\n\u0627\u062e\u062a\u064a\u0627\u0631 \u0627\u0644\u0639\u0645\u064a\u0644 \u0644\u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u062e\u062f\u0645\u0629: \u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u0645\u0639\u062a\u0645\u062f\u0629 \u0645\u0646 8:00 \u0645\u0633\u0627\u0621\u064b \u0625\u0644\u0649 10:00 \u0645\u0633\u0627\u0621\u064b.\n\nCustomer:\n\"\u0645\u0646 4 \u0625\u0644\u0649 7\"\n\nOutput:\n\u0627\u062e\u062a\u064a\u0627\u0631 \u0627\u0644\u0639\u0645\u064a\u0644 \u0644\u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u062e\u062f\u0645\u0629: \u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u0645\u0639\u062a\u0645\u062f\u0629 \u0645\u0646 4:00 \u0639\u0635\u0631\u064b\u0627 \u0625\u0644\u0649 7:00 \u0645\u0633\u0627\u0621\u064b.\n\n==================================================\nOTHER REQUESTED INFORMATION\n==================================================\n\nThis node may also receive valid requested information that is NOT a pickup time.\n\nFor example:\n- address confirmation\n- requested detail\n- other valid information requested to continue the resolution\n\nIn these cases:\n\n- preserve the customer's information accurately\n- make it clear and concise for the responsible team\n- do not add facts that the customer did not provide\n- do not apply pickup-period rules unless the information is actually about re-service scheduling\n\nExample:\n\nCustomer:\n\"\u0646\u0641\u0633 \u0627\u0644\u0639\u0646\u0648\u0627\u0646 \u0627\u0644\u0645\u0633\u062c\u0644\"\n\nOutput:\n\u0631\u062f \u0627\u0644\u0639\u0645\u064a\u0644 \u0628\u0627\u0644\u0645\u0639\u0644\u0648\u0645\u0629 \u0627\u0644\u0645\u0637\u0644\u0648\u0628\u0629 \u0644\u0627\u0633\u062a\u0643\u0645\u0627\u0644 \u0627\u0644\u062d\u0644: \u0623\u0643\u062f \u0627\u0644\u0639\u0645\u064a\u0644 \u0623\u0646 \u0627\u0644\u0639\u0646\u0648\u0627\u0646 \u0647\u0648 \u0646\u0641\u0633 \u0627\u0644\u0639\u0646\u0648\u0627\u0646 \u0627\u0644\u0645\u0633\u062c\u0644.\n\n==================================================\nFINAL OUTPUT RULE\n==================================================\n\nReturn ONLY the final Arabic internal note.\n\nDo not return JSON.\nDo not use markdown.\nDo not explain your reasoning.\nDo not include anything except the normalized note."
            }
          ]
        },
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.9,
      "position": [
        4112,
        1488
      ],
      "id": "4fdc6a10-0faa-4cf0-a51e-8e31afa73ae9",
      "name": "Normalize Requested Resolution Info"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "62e46801-907e-4ee2-870a-bfeee25b6d8a",
              "leftValue": "={{ $('Find Awaiting Customer Reply Issue').first().json.is_final_resolution }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        3824,
        2544
      ],
      "id": "23c311ba-c858-424a-abb6-0b1fa8ae1891",
      "name": "Is Final Resolution?"
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-5-mini",
          "mode": "list",
          "cachedResultName": "gpt-5-mini"
        },
        "responsesApiEnabled": false,
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        4176,
        2512
      ],
      "id": "30dbfc00-1162-4d80-badb-0a8f973381a5",
      "name": "OpenAI Chat Model9",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=\u0627\u0639\u062a\u0631\u0627\u0636 \u0627\u0644\u0639\u0645\u064a\u0644 \u0627\u0644\u062d\u0627\u0644\u064a:\n{{ $json.current_message || $('Prepare Agent Input').first().json.agent_input }}\n\n\u0627\u0644\u0645\u0634\u0643\u0644\u0629 \u0623\u0648 \u0627\u0644\u0637\u0644\u0628 \u0627\u0644\u0623\u0635\u0644\u064a:\n{{ $json.issue_description }}\n\n\u0627\u0644\u0642\u0631\u0627\u0631 \u0627\u0644\u0646\u0647\u0627\u0626\u064a \u0645\u0646 \u0627\u0644\u0642\u0633\u0645:\n{{ $json.department_resolution }}\n\n\u0622\u062e\u0631 \u0631\u0633\u0627\u0644\u0629 \u062a\u0645 \u0625\u0631\u0633\u0627\u0644\u0647\u0627 \u0644\u0644\u0639\u0645\u064a\u0644 \u0628\u062e\u0635\u0648\u0635 \u0627\u0644\u0642\u0631\u0627\u0631 \u0627\u0644\u0646\u0647\u0627\u0626\u064a:\n{{ $json.resolution_message_sent }}",
        "messages": {
          "messageValues": [
            {
              "message": "=You are a customer-facing assistant for Demo Laundry Laundry Customer Service in Saudi Arabia.\n\nThe customer is objecting to a resolution that has ALREADY been reviewed and explicitly marked as FINAL by the responsible team.\n\nYour ONLY task is to respond politely and professionally to the customer's objection without reopening negotiation or promising another review.\n\nYou receive:\n- the customer's current objection\n- the original issue\n- the final department decision\n- the last final-resolution message sent to the customer\n\n==================================================\nCORE RULE\n==================================================\n\nThe approved final resolution is authoritative.\n\nDo NOT:\n- change the final resolution\n- offer a different solution\n- increase compensation\n- promise additional compensation\n- promise another review\n- say the case will be sent back for reconsideration\n- imply that the decision may change\n- invent information\n\nThe purpose of this message is to respectfully explain that the resolution already communicated is the final approved resolution.\n\n==================================================\nRESPONSE BEHAVIOR\n==================================================\n\nAcknowledge the customer's objection respectfully without sounding argumentative or dismissive.\n\nClearly reinforce the actual final solution already communicated to the customer.\n\nWhen appropriate, explain that the final resolution was determined according to Demo Laundry's approved policy and terms and conditions.\n\nDo NOT use harsh phrases such as:\n- \"\u0647\u0630\u0627 \u0627\u0644\u0644\u064a \u0639\u0646\u062f\u0646\u0627\"\n- \"\u062e\u0644\u0627\u0635 \u0627\u0644\u0642\u0631\u0627\u0631 \u0646\u0647\u0627\u0626\u064a\"\n- \"\u0645\u0627 \u0646\u0642\u062f\u0631 \u0646\u0633\u0648\u064a \u0644\u0643 \u0634\u064a\u0621\"\n- \"\u0627\u0639\u062a\u0631\u0627\u0636\u0643 \u0645\u0631\u0641\u0648\u0636\"\n\nUse professional wording with the meaning of:\n\n\"\u0646\u062a\u0641\u0647\u0645 \u0645\u0644\u0627\u062d\u0638\u062a\u0643\u060c \u0648\u0628\u0639\u062f \u0645\u0631\u0627\u062c\u0639\u0629 \u0627\u0644\u062d\u0627\u0644\u0629 \u0641\u0625\u0646 \u0627\u0644\u062d\u0644 \u0627\u0644\u0645\u0631\u0633\u0644 \u0644\u0643 \u0647\u0648 \u0627\u0644\u0642\u0631\u0627\u0631 \u0627\u0644\u0646\u0647\u0627\u0626\u064a \u0627\u0644\u0645\u0639\u062a\u0645\u062f \u0648\u0641\u0642 \u0627\u0644\u0633\u064a\u0627\u0633\u0629 \u0648\u0627\u0644\u0634\u0631\u0648\u0637 \u0648\u0627\u0644\u0623\u062d\u0643\u0627\u0645. \u0646\u0634\u0643\u0631 \u062a\u0641\u0647\u0645\u0643.\"\n\nBut DO NOT blindly copy this sentence every time.\nAdapt the response naturally to the actual final resolution.\n\n==================================================\nIMPORTANT\n==================================================\n\nA final decision does NOT necessarily mean the operational process is complete.\n\nIf the final resolution still requires an action such as:\n- re-service\n- pickup\n- delivery\n- refund processing\n\ndo NOT tell the customer that the case is closed or completed.\n\nDo NOT cancel or stop the approved operational action.\n\nIf useful, briefly remind the customer of the approved final solution, but do not restart negotiation.\n\n==================================================\nSCHEDULING WORDING\n==================================================\n\nIf the final approved resolution still requires scheduling, use the correct wording based ONLY on the next action required from the customer.\n\nNever combine pickup and delivery wording.\n\nDo NOT say:\n- \"\u0641\u062a\u0631\u0627\u062a \u0627\u0644\u0627\u0633\u062a\u0644\u0627\u0645 \u0648\u0627\u0644\u062a\u0648\u0635\u064a\u0644\"\n- \"\u0645\u0648\u0639\u062f \u0627\u0644\u0627\u0633\u062a\u0644\u0627\u0645 \u0648\u0627\u0644\u062a\u0648\u0635\u064a\u0644\"\n- \"\u0627\u062e\u062a\u0631 \u0641\u062a\u0631\u0629 \u0644\u0644\u0627\u0633\u062a\u0644\u0627\u0645 \u0648\u0627\u0644\u062a\u0648\u0635\u064a\u0644\"\n\nIf Demo Laundry needs to collect an item from the customer for re-service, refer ONLY to pickup/collection using:\n\n\"\u0641\u062a\u0631\u0627\u062a \u0627\u0644\u0627\u0633\u062a\u0644\u0627\u0645\"\n\nor:\n\n\"\u0627\u062e\u062a\u0631 \u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u0645\u0646\u0627\u0633\u0628\u0629 \u0644\u0643 \u0644\u0644\u0627\u0633\u062a\u0644\u0627\u0645.\"\n\nIf Demo Laundry needs to deliver an item to the customer, such as returning a missing item, refer ONLY to delivery using:\n\n\"\u0641\u062a\u0631\u0627\u062a \u0627\u0644\u062a\u0648\u0635\u064a\u0644\"\n\nor:\n\n\"\u0627\u062e\u062a\u0631 \u0627\u0644\u0641\u062a\u0631\u0629 \u0627\u0644\u0645\u0646\u0627\u0633\u0628\u0629 \u0644\u0643 \u0644\u0644\u062a\u0648\u0635\u064a\u0644.\"\n\nChoose exactly ONE according to the next operational action.\n\nIf the customer was already sent the approved periods and still needs to choose one, you may briefly remind them to choose one of the previously sent periods.\n\nFor an approved re-service, if no period has been selected yet, the next required action is pickup from the customer, so use \"\u0627\u0644\u0627\u0633\u062a\u0644\u0627\u0645\", not \"\u0627\u0644\u062a\u0648\u0635\u064a\u0644\".\n\n==================================================\nSTYLE\n==================================================\n\nReply in natural Saudi Arabic.\n\nThe message must be:\n- respectful\n- calm\n- professional\n- concise\n- clear\n- normally 1 or 2 short sentences\n\nNo unnecessary greeting.\nDo not start with \"\u0623\u0643\u064a\u062f\" or \"\u0623\u0628\u0634\u0631\".\nAt most one light emoji if appropriate.\n\nNever mention:\n- ticket\n- Freshdesk\n- department\n- internal note\n- workflow\n- classifier\n- system\n\nReturn ONLY the exact customer-facing message.\n\nDo not return JSON.\nDo not explain your reasoning.\nDo not add labels."
            }
          ]
        },
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.9,
      "position": [
        4112,
        2288
      ],
      "id": "cd5bcc32-7a6f-4042-bc1b-e2b22a2d456e",
      "name": "Respond to Final Resolution Objection"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://YOUR_FRESHCHAT_DOMAIN.freshchat.com/v2/conversations/{{ $('Normalize Freshchat Event').item.json.conversation_id }}/messages",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_API_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Accept",
              "value": "application/json"
            },
            {
              "name": "ASSUME-IDENTITY",
              "value": "false"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"message_parts\": [\n    {\n      \"text\": {\n        \"content\": {{ JSON.stringify($json.text) }}\n      }\n    }\n  ],\n  \"message_type\": \"normal\",\n  \"actor_type\": \"bot\"\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        4464,
        2400
      ],
      "id": "848f3a3c-9dd6-4e4f-bf53-6397d7c57b43",
      "name": "Send Final Resolution Objection Reply to Customer"
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_SHEET_ID",
          "mode": "list",
          "cachedResultName": "Customer Service AI System",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit"
        },
        "sheetName": {
          "__rl": true,
          "value": 128263397,
          "mode": "list",
          "cachedResultName": "Issue Drafts",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEET_ID/edit#gid=YOUR_SHEET_GID"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "issue_id": "={{ $('Classify Related Resolution Reply').item.json.issue_id }}",
            "updated_at": "={{ $now.setZone('Asia/Riyadh').toFormat('yyyy-MM-dd HH:mm:ss') }}",
            "resolution_message_sent": "={{ $('Respond to Final Resolution Objection').item.json.text }}"
          },
          "matchingColumns": [
            "issue_id"
          ],
          "schema": [
            {
              "id": "issue_id",
              "displayName": "issue_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "conversation_id",
              "displayName": "conversation_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "conversation_internal_id",
              "displayName": "conversation_internal_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "customer_phone",
              "displayName": "customer_phone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "order_number",
              "displayName": "order_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "order_phone",
              "displayName": "order_phone",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "issue_description",
              "displayName": "issue_description",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "image_urls",
              "displayName": "image_urls",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "status",
              "displayName": "status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "is_active",
              "displayName": "is_active",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "ticket_id",
              "displayName": "ticket_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "updated_at",
              "displayName": "updated_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "ticket_type\n",
              "displayName": "ticket_type\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_1\n",
              "displayName": "level_1\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_2\n",
              "displayName": "level_2\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "level_3\n",
              "displayName": "level_3\n",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "department_resolution",
              "displayName": "department_resolution",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "resolution_message_sent",
              "displayName": "resolution_message_sent",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "is_final_resolution",
              "displayName": "is_final_resolution",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "row_number",
              "displayName": "row_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true,
              "readOnly": true,
              "removed": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        4688,
        2400
      ],
      "id": "c74f9646-ff8a-4ae9-950b-775a323af013",
      "name": "Update Last Final Resolution Reply",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "tableId": "resolution_reply_buffer",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "issue_id",
              "fieldValue": "={{ $json.issue_id }}"
            },
            {
              "fieldId": "conversation_id",
              "fieldValue": "={{ $json.conversation_id }}"
            },
            {
              "fieldId": "message_text",
              "fieldValue": "={{ $('Prepare Agent Input').first().json.agent_input }}"
            },
            {
              "fieldId": "message_id",
              "fieldValue": "={{ $('Normalize Freshchat Event').first().json.message_id }}"
            },
            {
              "fieldId": "message_time",
              "fieldValue": "={{ $('Normalize Freshchat Event').first().json.action_time }}"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        -448,
        1824
      ],
      "id": "e00c609c-f7f8-4465-a064-f2bf8e6b2900",
      "name": "Save Resolution Reply to Buffer",
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        -224,
        1824
      ],
      "id": "285a7c40-7478-4d8d-8d0e-e3c9ee2cd6df",
      "name": "Wait for More Resolution Replies"
    },
    {
      "parameters": {
        "operation": "get",
        "tableId": "resolution_reply_buffer",
        "filters": {
          "conditions": [
            {
              "keyName": "issue_id",
              "keyValue": "={{ $('Save Resolution Reply to Buffer').first().json.issue_id }}"
            },
            {
              "keyName": "conversation_id",
              "keyValue": "={{ $('Save Resolution Reply to Buffer').first().json.conversation_id }}"
            },
            {
              "keyName": "processed",
              "keyValue": "={{ false }}"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        0,
        1824
      ],
      "id": "2ddeb048-4afe-4448-9874-066ca00ac191",
      "name": "Get Unprocessed Resolution Replies",
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const rows = $input.all().map(item => item.json);\n\nconst currentMessageId =\n  $('Save Resolution Reply to Buffer').first().json.message_id;\n\nif (rows.length === 0) {\n  return [\n    {\n      json: {\n        is_latest_execution: false,\n        current_message_id: currentMessageId,\n        latest_message_id: null,\n        unprocessed_count: 0\n      }\n    }\n  ];\n}\n\n// \u062a\u0631\u062a\u064a\u0628 \u0627\u0644\u0631\u0633\u0627\u0626\u0644 \u0645\u0646 \u0627\u0644\u0623\u0642\u062f\u0645 \u0644\u0644\u0623\u062d\u062f\u062b\nrows.sort((a, b) => {\n  const timeA = new Date(a.message_time || a.created_at).getTime();\n  const timeB = new Date(b.message_time || b.created_at).getTime();\n\n  return timeA - timeB;\n});\n\nconst latestMessage = rows[rows.length - 1];\n\nreturn [\n  {\n    json: {\n      is_latest_execution:\n        latestMessage.message_id === currentMessageId,\n\n      current_message_id: currentMessageId,\n      latest_message_id: latestMessage.message_id,\n      unprocessed_count: rows.length\n    }\n  }\n];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        224,
        1824
      ],
      "id": "4e0ee077-6835-4eae-84b3-ee3a76b5b57e",
      "name": "Check Latest Resolution Reply"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "aeaf84b2-b3b0-4699-864b-0e10f90473eb",
              "leftValue": "={{ $json.is_latest_execution }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        -720,
        2048
      ],
      "id": "a31a474c-3fca-46db-8ee3-9708eb8ffcd1",
      "name": "Is Latest Resolution Reply?"
    },
    {
      "parameters": {
        "jsCode": "const rows = $('Get Unprocessed Resolution Replies')\n  .all()\n  .map(item => item.json);\n\n// \u0646\u0631\u062a\u0628 \u0631\u0633\u0627\u0626\u0644 \u0627\u0644\u0639\u0645\u064a\u0644 \u062d\u0633\u0628 \u0648\u0642\u062a \u0625\u0631\u0633\u0627\u0644\u0647\u0627 \u0627\u0644\u062d\u0642\u064a\u0642\u064a\nrows.sort((a, b) => {\n  const timeA = new Date(a.message_time || a.created_at).getTime();\n  const timeB = new Date(b.message_time || b.created_at).getTime();\n\n  return timeA - timeB;\n});\n\n// \u0646\u062c\u0645\u0639 \u0627\u0644\u0646\u0635\u0648\u0635 \u0628\u0627\u0644\u062a\u0631\u062a\u064a\u0628\nconst combinedMessage = rows\n  .map(row => (row.message_text || '').trim())\n  .filter(Boolean)\n  .join('\\n');\n\n// \u0646\u062d\u062a\u0641\u0638 \u0623\u064a\u0636\u064b\u0627 \u0628\u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0627\u0644\u0642\u0636\u064a\u0629 \u0627\u0644\u0623\u0635\u0644\u064a\u0629\nconst issue = $('Find Awaiting Customer Reply Issue').first().json;\n\nreturn [\n  {\n    json: {\n      ...issue,\n\n      current_message: combinedMessage,\n\n      buffered_message_count: rows.length,\n      buffered_message_ids: rows.map(row => row.message_id),\n      buffer_row_ids: rows.map(row => row.id)\n    }\n  }\n];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -448,
        2032
      ],
      "id": "6a2f422f-8883-43bd-98bf-a8b43f164477",
      "name": "Combine Resolution Replies"
    },
    {
      "parameters": {
        "jsCode": "const batch = $json;\n\nconst rowIds = Array.isArray(batch.buffer_row_ids)\n  ? batch.buffer_row_ids\n  : [];\n\nreturn rowIds.map(id => ({\n  json: {\n    ...batch,\n    buffer_row_id: id\n  }\n}));"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -224,
        2032
      ],
      "id": "b32f2527-5a04-4734-8dca-24066b5437b9",
      "name": "Prepare Resolution Buffer Rows for Update"
    },
    {
      "parameters": {
        "operation": "update",
        "tableId": "resolution_reply_buffer",
        "filters": {
          "conditions": [
            {
              "keyName": "id",
              "condition": "eq",
              "keyValue": "={{ $json.buffer_row_id }}"
            }
          ]
        },
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "processed",
              "fieldValue": "={{true}}"
            },
            {
              "fieldId": "processed_at",
              "fieldValue": "={{ $now.toISO() }}"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        0,
        2032
      ],
      "id": "c22169c8-84ad-418b-a8d7-179716541893",
      "name": "Mark Resolution Replies as Processed",
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const batch = $('Combine Resolution Replies').first().json;\n\nreturn [\n  {\n    json: batch\n  }\n];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        224,
        2032
      ],
      "id": "a13091f2-bd08-49e9-9813-6143dde827f1",
      "name": "Continue Once After Resolution Buffer Update"
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-5-mini",
          "mode": "list",
          "cachedResultName": "gpt-5-mini"
        },
        "responsesApiEnabled": false,
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        4176,
        2112
      ],
      "id": "67b9de78-04af-4241-a2cd-8bd6934bcc0a",
      "name": "OpenAI Chat Model10",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=\u0631\u0633\u0627\u0644\u0629 \u0627\u0644\u0639\u0645\u064a\u0644 \u0627\u0644\u062d\u0627\u0644\u064a\u0629:\n{{ $json.current_message || $('Prepare Agent Input').first().json.agent_input }}\n\n\u0627\u0644\u0645\u0634\u0643\u0644\u0629 \u0623\u0648 \u0627\u0644\u0637\u0644\u0628 \u0627\u0644\u0623\u0635\u0644\u064a:\n{{ $json.issue_description }}\n\n\u0642\u0631\u0627\u0631 \u0627\u0644\u0642\u0633\u0645 \u0627\u0644\u0645\u062e\u062a\u0635:\n{{ $json.department_resolution }}\n\n\u0622\u062e\u0631 \u0631\u0633\u0627\u0644\u0629 \u0623\u0631\u0633\u0644\u0646\u0627\u0647\u0627 \u0644\u0644\u0639\u0645\u064a\u0644 \u0628\u062e\u0635\u0648\u0635 \u0627\u0644\u062d\u0644:\n{{ $json.resolution_message_sent }}",
        "messages": {
          "messageValues": [
            {
              "message": "=\u0623\u0646\u062a \u0645\u0633\u0624\u0648\u0644 \u0639\u0646 \u0635\u064a\u0627\u063a\u0629 \u0631\u0633\u0627\u0644\u0629 \u062a\u0648\u0636\u064a\u062d\u064a\u0629 \u0642\u0635\u064a\u0631\u0629 \u0644\u0644\u0639\u0645\u064a\u0644 \u0639\u0646\u062f\u0645\u0627 \u062d\u0627\u0648\u0644 \u062a\u0642\u062f\u064a\u0645 \u0627\u0644\u0645\u0639\u0644\u0648\u0645\u0629 \u0627\u0644\u0645\u0637\u0644\u0648\u0628\u0629 \u0644\u0627\u0633\u062a\u0643\u0645\u0627\u0644 \u0627\u0644\u062d\u0644\u060c \u0644\u0643\u0646 \u0631\u062f\u0647 \u0643\u0627\u0646 \u0646\u0627\u0642\u0635\u064b\u0627 \u0623\u0648 \u063a\u064a\u0631 \u0635\u0627\u0644\u062d \u0644\u0644\u062a\u0646\u0641\u064a\u0630.\n\n\u0645\u0647\u0645\u062a\u0643:\n\u062d\u062f\u062f \u0623\u0648\u0644\u064b\u0627 \u0645\u0646 \"\u0622\u062e\u0631 \u0631\u0633\u0627\u0644\u0629 \u0623\u0631\u0633\u0644\u0646\u0627\u0647\u0627 \u0644\u0644\u0639\u0645\u064a\u0644 \u0628\u062e\u0635\u0648\u0635 \u0627\u0644\u062d\u0644\" \u0645\u0627 \u0647\u064a \u0627\u0644\u0645\u0639\u0644\u0648\u0645\u0629 \u0623\u0648 \u0627\u0644\u0625\u062c\u0631\u0627\u0621 \u0627\u0644\u0645\u0637\u0644\u0648\u0628 \u0645\u0646 \u0627\u0644\u0639\u0645\u064a\u0644\u060c \u062b\u0645 \u0627\u0637\u0644\u0628 \u0645\u0646\u0647 \u0641\u0642\u0637 \u062a\u0635\u062d\u064a\u062d \u0623\u0648 \u0627\u0633\u062a\u0643\u0645\u0627\u0644 \u0647\u0630\u0647 \u0627\u0644\u0645\u0639\u0644\u0648\u0645\u0629.\n\n\u0627\u0644\u0642\u0648\u0627\u0639\u062f:\n\n1. \u0627\u0643\u062a\u0628 \u0628\u0627\u0644\u0639\u0631\u0628\u064a\u0629 \u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629 \u0627\u0644\u0637\u0628\u064a\u0639\u064a\u0629 \u0648\u0628\u0634\u0643\u0644 \u0645\u062e\u062a\u0635\u0631 \u0648\u0648\u0627\u0636\u062d.\n\n2. \u0644\u0627 \u062a\u062e\u062a\u0631\u0639 \u0623\u064a \u0645\u0639\u0644\u0648\u0645\u0629 \u0623\u0648 \u0625\u062c\u0631\u0627\u0621 \u063a\u064a\u0631 \u0645\u0648\u062c\u0648\u062f \u0641\u064a \u0627\u0644\u0633\u064a\u0627\u0642.\n\n3. \u0644\u0627 \u062a\u063a\u064a\u0651\u0631 \u0627\u0644\u062d\u0644 \u0627\u0644\u0645\u0639\u062a\u0645\u062f \u0645\u0646 \u0627\u0644\u0642\u0633\u0645.\n\n4. \u0644\u0627 \u062a\u0639\u064a\u062f \u0634\u0631\u062d \u0627\u0644\u0645\u0634\u0643\u0644\u0629 \u0643\u0627\u0645\u0644\u0629 \u0648\u0644\u0627 \u062a\u0630\u0643\u0631 Freshdesk \u0623\u0648 \u0627\u0644\u0642\u0633\u0645 \u0623\u0648 \u0627\u0644\u0623\u0646\u0638\u0645\u0629 \u0627\u0644\u062f\u0627\u062e\u0644\u064a\u0629.\n\n5. \u0625\u0630\u0627 \u0643\u0627\u0646 \u0627\u0644\u0645\u0637\u0644\u0648\u0628 \u0627\u062e\u062a\u064a\u0627\u0631 \u0641\u062a\u0631\u0629 \u0644\u0644\u0627\u0633\u062a\u0644\u0627\u0645\u060c \u0641\u0644\u0627 \u062a\u0642\u0628\u0644 \"\u0627\u0644\u0622\u0646\" \u0623\u0648 \"\u0628\u0639\u062f \u0634\u0648\u064a\" \u0623\u0648 \"\u0623\u064a \u0648\u0642\u062a\" \u0623\u0648 \u0648\u0642\u062a\u064b\u0627 \u062e\u0627\u0631\u062c \u0627\u0644\u0641\u062a\u0631\u0627\u062a \u0627\u0644\u0645\u0639\u062a\u0645\u062f\u0629.\n\n\u0627\u0644\u0641\u062a\u0631\u0627\u062a \u0627\u0644\u0645\u0639\u062a\u0645\u062f\u0629 \u0644\u0644\u0627\u0633\u062a\u0644\u0627\u0645 \u0647\u064a \u0641\u0642\u0637:\n\u2022 \u0645\u0646 11:00 \u0635\u0628\u0627\u062d\u064b\u0627 \u0625\u0644\u0649 3:00 \u0639\u0635\u0631\u064b\u0627\n\u2022 \u0645\u0646 4:00 \u0639\u0635\u0631\u064b\u0627 \u0625\u0644\u0649 7:00 \u0645\u0633\u0627\u0621\u064b\n\u2022 \u0645\u0646 8:00 \u0645\u0633\u0627\u0621\u064b \u0625\u0644\u0649 10:00 \u0645\u0633\u0627\u0621\u064b\n\n\u0641\u064a \u0647\u0630\u0647 \u0627\u0644\u062d\u0627\u0644\u0629 \u0627\u0637\u0644\u0628 \u0645\u0646 \u0627\u0644\u0639\u0645\u064a\u0644 \u0627\u062e\u062a\u064a\u0627\u0631 \u0625\u062d\u062f\u0649 \u0627\u0644\u0641\u062a\u0631\u0627\u062a \u0627\u0644\u062b\u0644\u0627\u062b\u060c \u0648\u0627\u0639\u0631\u0636 \u0643\u0644 \u0641\u062a\u0631\u0629 \u0641\u064a \u0633\u0637\u0631 \u0645\u0633\u062a\u0642\u0644.\n\n6. \u0625\u0630\u0627 \u0643\u0627\u0646 \u0627\u0644\u0645\u0637\u0644\u0648\u0628 \u0627\u062e\u062a\u064a\u0627\u0631 \u0641\u062a\u0631\u0629 \u0644\u0644\u062a\u0648\u0635\u064a\u0644\u060c \u0627\u0633\u062a\u062e\u062f\u0645 \u0646\u0641\u0633 \u0627\u0644\u0641\u062a\u0631\u0627\u062a \u0627\u0644\u0645\u0639\u062a\u0645\u062f\u0629 \u0648\u0644\u0643\u0646 \u0642\u0644 \"\u0644\u0644\u062a\u0648\u0635\u064a\u0644\" \u0648\u0644\u064a\u0633 \"\u0644\u0644\u0627\u0633\u062a\u0644\u0627\u0645\".\n\n7. \u0644\u0627 \u062a\u0633\u062a\u062e\u062f\u0645 \u0639\u0628\u0627\u0631\u0629 \"\u0627\u0644\u0627\u0633\u062a\u0644\u0627\u0645 \u0648\u0627\u0644\u062a\u0648\u0635\u064a\u0644\" \u0645\u0639\u064b\u0627. \u062d\u062f\u062f \u0648\u0627\u062d\u062f\u0629 \u0641\u0642\u0637 \u062d\u0633\u0628 \u0627\u0644\u0625\u062c\u0631\u0627\u0621 \u0627\u0644\u0645\u0637\u0644\u0648\u0628.\n\n8. \u0625\u0630\u0627 \u0643\u0627\u0646 \u0627\u0644\u0645\u0637\u0644\u0648\u0628 \u0635\u0648\u0631\u0629:\n\u0627\u0637\u0644\u0628 \u0645\u0646 \u0627\u0644\u0639\u0645\u064a\u0644 \u0625\u0631\u0633\u0627\u0644 \u0627\u0644\u0635\u0648\u0631\u0629 \u0627\u0644\u0645\u0637\u0644\u0648\u0628\u0629 \u0628\u0648\u0636\u0648\u062d.\n\u0644\u0627 \u062a\u0631\u0633\u0644 \u0644\u0647 \u0641\u062a\u0631\u0627\u062a \u0627\u0644\u0627\u0633\u062a\u0644\u0627\u0645.\n\n9. \u0625\u0630\u0627 \u0643\u0627\u0646 \u0627\u0644\u0645\u0637\u0644\u0648\u0628 \u0645\u0648\u0642\u0639\u064b\u0627 \u0623\u0648 \u0639\u0646\u0648\u0627\u0646\u064b\u0627:\n\u0627\u0637\u0644\u0628 \u0645\u0646\u0647 \u0625\u0631\u0633\u0627\u0644 \u0623\u0648 \u062a\u0623\u0643\u064a\u062f \u0627\u0644\u0645\u0648\u0642\u0639/\u0627\u0644\u0639\u0646\u0648\u0627\u0646 \u0627\u0644\u0645\u0637\u0644\u0648\u0628.\n\u0644\u0627 \u062a\u0631\u0633\u0644 \u0644\u0647 \u0641\u062a\u0631\u0627\u062a \u0627\u0644\u0627\u0633\u062a\u0644\u0627\u0645.\n\n10. \u0625\u0630\u0627 \u0643\u0627\u0646 \u0627\u0644\u0645\u0637\u0644\u0648\u0628 \u062a\u0623\u0643\u064a\u062f \u0645\u0639\u0644\u0648\u0645\u0629 \u0645\u0639\u064a\u0646\u0629:\n\u0627\u0637\u0644\u0628 \u0645\u0646\u0647 \u062a\u0623\u0643\u064a\u062f \u0647\u0630\u0647 \u0627\u0644\u0645\u0639\u0644\u0648\u0645\u0629 \u0641\u0642\u0637.\n\n11. \u0625\u0630\u0627 \u0643\u0627\u0646 \u0627\u0644\u0639\u0645\u064a\u0644 \u0642\u062f \u062d\u0627\u0648\u0644 \u0627\u0644\u0625\u062c\u0627\u0628\u0629 \u0644\u0643\u0646 \u0625\u062c\u0627\u0628\u062a\u0647 \u063a\u0627\u0645\u0636\u0629\u060c \u0648\u0636\u0651\u062d \u0644\u0647 \u062a\u062d\u062f\u064a\u062f\u064b\u0627 \u0645\u0627 \u0627\u0644\u0630\u064a \u0646\u062d\u062a\u0627\u062c\u0647 \u0645\u0646\u0647.\n\n12. \u0644\u0627 \u062a\u0642\u0644 \u0644\u0644\u0639\u0645\u064a\u0644 \u0625\u0646 \u0631\u062f\u0647 \"\u063a\u064a\u0631 \u0635\u0627\u0644\u062d\" \u0623\u0648 \"\u062e\u0637\u0623\". \u0627\u0633\u062a\u062e\u062f\u0645 \u0635\u064a\u0627\u063a\u0629 \u0644\u0637\u064a\u0641\u0629 \u0648\u0645\u0628\u0627\u0634\u0631\u0629.\n\n13. \u0623\u062e\u0631\u062c \u0641\u0642\u0637 \u0627\u0644\u0631\u0633\u0627\u0644\u0629 \u0627\u0644\u0646\u0647\u0627\u0626\u064a\u0629 \u0627\u0644\u062a\u064a \u0633\u062a\u0631\u0633\u0644 \u0644\u0644\u0639\u0645\u064a\u0644\u060c \u0628\u062f\u0648\u0646 \u0634\u0631\u062d \u0623\u0648 \u062a\u062d\u0644\u064a\u0644."
            }
          ]
        },
        "batching": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.9,
      "position": [
        4112,
        1888
      ],
      "id": "ec0886e3-e9bf-48e2-b7a3-dc1c7b43ea17",
      "name": "Generate Requested Info Clarification"
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-5.6-sol",
          "mode": "list",
          "cachedResultName": "gpt-5.6-sol"
        },
        "builtInTools": {},
        "options": {
          "textFormat": {
            "textOptions": {
              "type": "text"
            }
          },
          "reasoningEffort": "medium",
          "timeout": 180000,
          "maxRetries": 2
        }
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        704,
        2096
      ],
      "id": "6399e72e-2ba2-430f-94e8-bdefb5c8673f",
      "name": "OpenAI Chat Model11",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "toolDescription": "Retrieves protected customer/order metadata needed by the support workflow. Production endpoint and field details are omitted.",
        "method": "POST",
        "url": "https://YOUR_INTERNAL_API_DOMAIN/apis/analytics/user",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": " Bearer YOUR_API_TOKEN"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "mobile",
              "value": "={{\n(() => {\n  const currentPhone = String(\n    $('Build Customer Context').first().json.customer_phone || ''\n  )\n    .replace(/\\D/g, '')\n    .trim();\n\n  const aiPhone = String(\n    $fromAI(\n      'metrics_lookup_phone',\n      'Return ONLY the exact phone number that must be used for Demo Customer Metrics. If the customer explicitly confirmed an alternate order phone, return that exact phone with country code. If the current conversation phone should be used, return an empty string. Never guess or invent a phone number.',\n      'string',\n      ''\n    ) || ''\n  )\n    .replace(/\\D/g, '')\n    .trim();\n\n  let savedOrderPhone = '';\n\n  try {\n    savedOrderPhone = String(\n      $('Get Current Issue Draft').first().json.order_phone || ''\n    )\n      .replace(/\\D/g, '')\n      .trim();\n  } catch (e) {\n    savedOrderPhone = '';\n  }\n\n  const phoneToUse =\n    aiPhone ||\n    savedOrderPhone ||\n    currentPhone;\n\n  if (!phoneToUse) {\n    throw new Error(\n      'A valid phone number is required for Demo Customer Metrics.'\n    );\n  }\n\n  return phoneToUse;\n})()\n}}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequestTool",
      "typeVersion": 4.4,
      "position": [
        1728,
        2096
      ],
      "id": "ce5acc49-c828-45f1-9dc3-94c87879d369",
      "name": "Demo Customer Metrics"
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Normalize Freshchat Event",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Freshchat Event": {
      "main": [
        [
          {
            "node": "Route Freshchat Event",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route Freshchat Event": {
      "main": [
        [
          {
            "node": "Save Paused State",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Save Active State",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Get Conversation State",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Conversation State": {
      "main": [
        [
          {
            "node": "Is AI Active?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is AI Active?": {
      "main": [
        [
          {
            "node": "Get Freshchat Customer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Freshchat Customer": {
      "main": [
        [
          {
            "node": "Build Customer Context",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Customer Context": {
      "main": [
        [
          {
            "node": "Has Images?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Images?": {
      "main": [
        [
          {
            "node": "Save Message to Buffer1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Get Pending Images Before Text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for More Images": {
      "main": [
        [
          {
            "node": "Get Unprocessed Image Buffer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Keep Latest Image Batch": {
      "main": [
        [
          {
            "node": "Get Collecting Issue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Collecting Issue": {
      "main": [
        [
          {
            "node": "Collecting Issue Exists?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Collecting Issue Exists?": {
      "main": [
        [
          {
            "node": "Merge New Images Into Draft",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Prepare Agent Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge New Images Into Draft": {
      "main": [
        [
          {
            "node": "Update Issue Draft Images",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Issue Draft Images": {
      "main": [
        [
          {
            "node": "Prepare Buffer IDs for Update",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Simple Memory": {
      "ai_memory": [
        [
          {
            "node": "Demo Customer Service Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Demo Customer Service Agent": {
      "main": [
        [
          {
            "node": "Send Customer Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Agent Input": {
      "main": [
        [
          {
            "node": "Find Awaiting Customer Reply Issue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If": {
      "main": [
        []
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Demo Customer Service Agent",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Send Customer Reply": {
      "main": [
        [
          {
            "node": "Route Media Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route Media Response": {
      "main": [
        [
          {
            "node": "Send Bag Info",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send Bag Image",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send Plastic Bag Image",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send How To Order Image",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send How To Hang Bag Image",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Plastic Bag Image": {
      "main": [
        []
      ]
    },
    "Send Bag Info": {
      "main": [
        []
      ]
    },
    "Send How To Order Image": {
      "main": [
        []
      ]
    },
    "create_freshdesk_ticket": {
      "ai_tool": [
        [
          {
            "node": "Demo Customer Service Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Get Order Status": {
      "ai_tool": [
        [
          {
            "node": "Demo Customer Service Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Get Current Issue Draft": {
      "ai_tool": [
        [
          {
            "node": "Demo Customer Service Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Update Issue Draft": {
      "ai_tool": [
        [
          {
            "node": "Demo Customer Service Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Save Issue Draft": {
      "ai_tool": [
        [
          {
            "node": "Demo Customer Service Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Continue Once After Buffer Update": {
      "main": [
        [
          {
            "node": "Prepare Agent Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Message to Buffer1": {
      "main": [
        [
          {
            "node": "Wait for More Images",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Unprocessed Image Buffer": {
      "main": [
        [
          {
            "node": "Keep Latest Image Batch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Buffer IDs for Update": {
      "main": [
        [
          {
            "node": "Mark Buffer Images as Processed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark Buffer Images as Processed": {
      "main": [
        [
          {
            "node": "Continue Once After Buffer Update",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Pending Images Before Text": {
      "main": [
        [
          {
            "node": "Check Recent Pending Images",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Recent Pending Images": {
      "main": [
        [
          {
            "node": "Recent Pending Image?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Recent Pending Image?": {
      "main": [
        [
          {
            "node": "Save Message to Buffer1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Prepare Agent Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Abandon Current Issue Draft": {
      "ai_tool": [
        [
          {
            "node": "Demo Customer Service Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "Structured Output Parser",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Find Awaiting Customer Reply Issue": {
      "main": [
        [
          {
            "node": "Has Awaiting Customer Reply Issue?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Awaiting Customer Reply Issue?": {
      "main": [
        [
          {
            "node": "Save Resolution Reply to Buffer",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Demo Customer Service Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model3": {
      "ai_languageModel": [
        [
          {
            "node": "Classify Customer Reply to Resolution",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model4": {
      "ai_languageModel": [
        [
          {
            "node": "Classify Related Resolution Reply",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Classify Customer Reply to Resolution": {
      "main": [
        [
          {
            "node": "Classify Related Resolution Reply",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Demo Customer Service Agent",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Split Mixed Customer Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Classify Related Resolution Reply": {
      "main": [
        [
          {
            "node": "Send Resolution Acceptance Confirmation",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Validate Requested Resolution Info",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Is Final Resolution?",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Answer Question About Resolution1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Customer Reply to Ticket": {
      "main": [
        [
          {
            "node": "Set Ticket Back to Pending",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Ticket Back to Pending": {
      "main": [
        [
          {
            "node": "Send Review Confirmation to Customer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Review Confirmation to Customer": {
      "main": [
        [
          {
            "node": "Set Issue Back to Pending",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Resolution Acceptance Confirmation": {
      "main": [
        [
          {
            "node": "Mark Issue Resolved After Acceptance",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Requested Info to Ticket": {
      "main": [
        [
          {
            "node": "Set Ticket Pending After Requested Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Ticket Pending After Requested Info": {
      "main": [
        [
          {
            "node": "Send Requested Info Confirmation to Customer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Requested Info Confirmation to Customer": {
      "main": [
        [
          {
            "node": "Set Issue Pending After Requested Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Issue Pending After Requested Info": {
      "main": [
        []
      ]
    },
    "OpenAI Chat Model5": {
      "ai_languageModel": [
        [
          {
            "node": "Answer Question About Resolution1",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model6": {
      "ai_languageModel": [
        [
          {
            "node": "Split Mixed Customer Message",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser2": {
      "ai_outputParser": [
        [
          {
            "node": "Split Mixed Customer Message",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Split Mixed Customer Message": {
      "main": [
        [
          {
            "node": "Prepare Mixed Related Part",
            "type": "main",
            "index": 0
          },
          {
            "node": "Prepare Mixed Unrelated Part",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Mixed Related Part": {
      "main": [
        [
          {
            "node": "Classify Related Resolution Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Mixed Unrelated Part": {
      "main": [
        [
          {
            "node": "Demo Customer Service Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Answer Question About Resolution1": {
      "main": [
        [
          {
            "node": "Answer Question About Resolution2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model7": {
      "ai_languageModel": [
        [
          {
            "node": "Validate Requested Resolution Info",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Validate Requested Resolution Info": {
      "main": [
        [
          {
            "node": "Normalize Requested Resolution Info",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Generate Requested Info Clarification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Available Pickup Periods to Customer": {
      "main": [
        [
          {
            "node": "Update Last Resolution Message After Invalid Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model8": {
      "ai_languageModel": [
        [
          {
            "node": "Normalize Requested Resolution Info",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Requested Resolution Info": {
      "main": [
        [
          {
            "node": "Add Requested Info to Ticket",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Final Resolution?": {
      "main": [
        [
          {
            "node": "Respond to Final Resolution Objection",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Add Customer Reply to Ticket",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model9": {
      "ai_languageModel": [
        [
          {
            "node": "Respond to Final Resolution Objection",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Respond to Final Resolution Objection": {
      "main": [
        [
          {
            "node": "Send Final Resolution Objection Reply to Customer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Final Resolution Objection Reply to Customer": {
      "main": [
        [
          {
            "node": "Update Last Final Resolution Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Resolution Reply to Buffer": {
      "main": [
        [
          {
            "node": "Wait for More Resolution Replies",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for More Resolution Replies": {
      "main": [
        [
          {
            "node": "Get Unprocessed Resolution Replies",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Unprocessed Resolution Replies": {
      "main": [
        [
          {
            "node": "Check Latest Resolution Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Latest Resolution Reply": {
      "main": [
        [
          {
            "node": "Is Latest Resolution Reply?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Latest Resolution Reply?": {
      "main": [
        [
          {
            "node": "Combine Resolution Replies",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Combine Resolution Replies": {
      "main": [
        [
          {
            "node": "Prepare Resolution Buffer Rows for Update",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Resolution Buffer Rows for Update": {
      "main": [
        [
          {
            "node": "Mark Resolution Replies as Processed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark Resolution Replies as Processed": {
      "main": [
        [
          {
            "node": "Continue Once After Resolution Buffer Update",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Continue Once After Resolution Buffer Update": {
      "main": [
        [
          {
            "node": "Classify Customer Reply to Resolution",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model10": {
      "ai_languageModel": [
        [
          {
            "node": "Generate Requested Info Clarification",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Generate Requested Info Clarification": {
      "main": [
        [
          {
            "node": "Send Available Pickup Periods to Customer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Demo Customer Metrics": {
      "ai_tool": [
        [
          {
            "node": "Demo Customer Service Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model11": {
      "ai_languageModel": [
        [
          {
            "node": "Demo Customer Service Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate"
  },
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "tags": []
}