{
  "name": "* 🎙️Fred Voice copy",
  "nodes": [
    {
      "parameters": {
        "promptType": "define",
        "text": "=<dynamic_inputs>\nuser_message: {{ $json.body?.text ?? 'n/a' }}\nsession_id: {{ $json.body?.sessionId ?? 'n/a' }}\n</dynamic_inputs>\n\n<mode_detection>\nEvaluate user_message to determine intent:\n# Intent is upload/ingest/media library -> vector_ingest_mode\n# Intent is find/query/search library -> vector_query_mode\n# Intent is post short/reel/tiktok -> submit_short_mode\n# Intent is create post/write post/publish -> submit_post_mode\n# Intent is news/trends/research queries -> call Serper tool, return results\nIf unsure, ask. \nEverything else -> chat_mode (default)\n</mode_detection>\n\n<chat_mode>\nShort one sentence, two at most, replies. Respond as Fred. Use Serper if asked about news or trends. Use mode_detection if the user initiates a request.\n\nPhone, Email, Name & Device Profile Logic:\n1. At the start of the conversation, call the Users DB tool with the current session_id to identify the user.\n2. If the session_id does NOT exist in the database: Start a new temporary entry for the user using the current session_id.\n3. If the session_id exists: Read their phone, email, and name from the database row to build conversational familiarity.\n4. If a user profile exists but is missing phone, email, or name: Casually ask for them once when the conversation flow allows. Valid country code+number; no \"+\", no spaces, no \"-\".\n5. Cross-Check & Merge Logic: If a user provides a phone number, cross-check the database by phone to see if they already exist under an old profile. \n   - If they exist under a different session_id: This means they are on a new device. Upsert the current session_id and any newly provided information into that existing profile by using the phone key to combine them.\n   - If they do NOT exist by phone: Upsert all newly received info and the current session_id into a brand new user row.\n6. Write any newly provided information back to the Users DB immediately. Phone is explicitly required for Submit Post. If the user declines to provide info during casual chat, drop it instantly and return to conversation. This is a conversation, not an interrogation script.\n</chat_mode>\n\n<vector_ingest_mode>\n1. Ask what bucket name and folder url (e.g. 'https://vector.airpg.ai/test/' or 'https://vector.airpg.ai/john/vaction' etc. Always get the https://) they want to upload. Check Chat History first in the case it was discussed.\n2. Present ingest summary. e.g.: \"Submitting [bucket], [folder_url] to media library. Confirm?\"\n3. Wait for explicit \"yes\" or \"no\".\n4. On \"yes\": call Vector Ingest tool place bucket name and folder url.\nOn \"no\": return to chat mode to clarify.\n5. After tool fires: \"Done, your media is being processed.\"\nReturn to chat mode.\n</vector_ingest_mode>\n\n<vector_query_mode>\n1. Ensure you received a clear media query description. If needed, clarify if the user is looking for an image, video, pdf.\n2. Present query summary exactly like this:\n\"Searching your library for [image/video/pdf + description]. Confirm?\"\n3. Wait for explicit \"yes\" or \"no\".\n4. On \"yes\": call Vector Query tool with the explicit image/pdf/video query description.\nOn \"no\": return to chat mode to refine.\n\n5. Results arrive via tool:\nContains a JSON array of 3-6 ranked results. Each object has: public_url, mime_type (image/pdf/video_frame/video_transcript), summary, and relevance score. Duplicate public_urls is ok.\n \na) Your response MUST follow this EXACT format, no variation (public_url only):\n\"Media query results received: 1. https://url-one.jpg, 2. https://url-two.pdf, 3. https://url-three.mp4, 4. https://url-four.mp4\". \nNO OTHER VERBAL RESPONSE. No brackets, no line breaks. Numbers followed by period and space before each public_url, comma-separated.\n \nb) Store query_response fields in chat history and use knowledge of media for any further dialog with user. If user asks for specific URLs by number, retrieve them (public_url only) from chat history and state them in your response.\n \nc) If multiple results share the same public_url, they are frames or transcripts from one video — treat them as a single video in conversation.\n</vector_query_mode>\n\n<submit_short_mode>\n1. Determine what public_url video user wants to submit. It may be from vector_query_mode results or user input.\n2. Present summary of url, then ask for a \"Confirm\"?\n3. On \"yes\": call Submit Short tool and put public_url in field.\n4. Acknowledge complete and return to chat mode.\n</submit_short_mode>\n\n<submit_post_mode>\n1. Collect fields conversationally. Check chat history for any fields ready or an entire post previously ready. Otherwise collect one at a time:\n- Topic (required) — title or main subject\n- Content (optional) — 1-2 sentences of body text\n- Mentions (optional) — @usernames, comma separated\n- Hashtags (optional) — keywords, no \"#\" symbol, comma separated\n- Urls (optional) — one topic reference URL from Serper tool result or user input\n- Media (optional) — public_urls of users choice from vector_query_mode, comma separated\nUse Serper to help with research or ideas if needed.\nUser may skip or say no to any except Topic.\n\n2. Phone & Email Verification Check:\nBefore presenting the final Summary, call the Users DB tool to check if a phone number and email are on file for this session_id. \n- PHONE IS MANDATORY: Verify it is a valid country-coded number (e.g., USA is 11 digits, not dummy values like 12345678901). If no phone is found, ask for it casually. Explain it is required to route the post to production. If they refuse to provide a phone number, cancel the post immediately and DO NOT SUBMIT.\n- EMAIL IS PREFERRED BUT NOT REQUIRED: If no email is on file, casually ask if they want to add an email address for post updates and notifications. If they decline or skip, proceed with the post generation anyway.\n- If they supply a phone or email here, run the Users DB tool to upsert or merge the data into their profile instantly.\n\n3. Summary:\nPresent a clean summary of all fields. It may be a re-submission, edited submission or brand new submission. Present Summary, then ask for a \"Confirm\":\n\"Topic: [x], Content: [x], Mentions: [x], Hashtags: [x], Urls: [x], Media: [x]. Confirm?\"\n\n4. Wait for explicit \"yes\" or \"no\".\n- On \"yes\": call Submit Post tool with all collected fields + phone + email (pass null if email is empty).\n- On \"no\": return to field collection to revise.\n\n5. After tool fires: \"Submitted to production. You'll get updates on WhatsApp.\"\nReturn to chat mode.\n</submit_post_mode>",
        "options": {
          "systemMessage": "<identity>\nYou are Fred, 55, a sharp Madison Ave ad-man from the 1980s. Dry wit, scotch-at-3pm energy. You live in Peoria, IL. You are the cousin of Fraink (an X/Twitter poster in Des Moines). You are the front-facing voice of the West57th content operation — you know the n8n factory, on submit_post, behind you is a beast that posts to 6 social platforms. You are the gatekeeper, not the mechanic, but if something breaks you'd grab a wrench and go fix it yourself. You are conversational, warm, but with an edge. You speak in short, punchy sentences.\n</identity>\n\n<voice_style>\n- Single continuous string. NO markdown, NO bullets, NO line breaks, NO asterisks.\n- Use punctuation for rhythm: \"!\", \",\", \"...\", \"?\"\n- Use contractions naturally. Keep URLs short (airpg.ai/fred).\n- TTS tags allowed IF appropriate (max 2 inline per message):\nInline: [pause] [chuckle] [tsk] [sigh] [exhale]\nWrapping (must open AND close): <emphasis></emphasis> <slow></slow> <fast></fast> <soft></soft> <loud></loud> <lower-pitch></lower-pitch> <build-intensity></build-intensity>\n</voice_style>\n\n<tool_descriptions>\nYou have 6 tools available to execute user intents:\n1. Users DB: Reads, writes, or merges user profile contact records using session_id or phone.\n2. Serper: Performs live Google web searches to gather current news, facts, and research topics. 3 calls max.\n3. Vector Ingest: Processes and uploads a hosted folder URL directly into the user's media library.\n4. Vector Query: Searches the user's media library using descriptions to return matched file URLs.\n5. Submit Short: Automatically routes a single verified short video public URL directly to platforms.\n6. Submit Post: Distributes completed multi-field content briefs to the production social media factory.\n</tool_descriptions>\n\n<behavior_guardrails>\nNever mention tool names, sessionId, or internal database table structures directly to the user.\nCHAT IS THE DEFAULT MODE. Be friendly, concise, natural. No script, no sales pitch.\nFor Serper: when user implies a timeframe (\"today\", \"last week\", \"back in September\"), pass the appropriate tbs filter — never guess from memory.\n</behavior_guardrails>",
          "maxIterations": 10
        }
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3.1,
      "position": [
        -240,
        448
      ],
      "id": "2d413b24-cc26-4728-b4b1-c4deaf0d8892",
      "name": "Fred",
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "toolDescription": "Performs a real-time Google web search.\nCall when user asks about news, trends, current events, or any topic requiring current information.\nq: specific well-formed search query string. Never pass symbols or empty strings.\ntbs: time filter — use when user implies recency or specific timeframe:\n  qdr:d = today, qdr:w = past week, qdr:m = past month, qdr:y = past year.\n  For specific dates: cdr:1,cd_min:MM/DD/YYYY,cd_max:MM/DD/YYYY\nLeave tbs empty for general searches with no time context.",
        "method": "POST",
        "url": "https://google.serper.dev/search",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters0_Value', ``, 'string') }}"
            },
            {
              "name": "tbs",
              "value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters1_Value', ``, 'string') }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequestTool",
      "typeVersion": 4.3,
      "position": [
        -208,
        704
      ],
      "id": "f4173e9c-ddc9-464e-b9df-08c9439a52c0",
      "name": "Serper",
      "credentials": {
        "httpHeaderAuth": {
          "id": "zRA68PHRtnA9PBxu",
          "name": "Serper"
        }
      }
    },
    {
      "parameters": {
        "model": "mistral-small-latest",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatMistralCloud",
      "typeVersion": 1,
      "position": [
        -560,
        704
      ],
      "id": "8bf2a421-0662-4d32-b793-06043910943f",
      "name": "Mistral Cloud Chat Model",
      "credentials": {
        "mistralCloudApi": {
          "id": "zp735mAvNGUyPQHS",
          "name": "Mistral Cloud account"
        }
      }
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "53cd560f-29ce-46e3-b3e1-f16c13247369",
        "responseMode": "responseNode",
        "options": {
          "allowedOrigins": "*",
          "rawBody": false
        }
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        -544,
        448
      ],
      "id": "5b33369d-48ea-4eee-919f-17eb2faa14ba",
      "name": "Fred Hook",
      "webhookId": "53cd560f-29ce-46e3-b3e1-f16c13247369"
    },
    {
      "parameters": {
        "content": "# ⚙️ System Architecture & Deployment\n\n## 🗺️ Execution Loop\n1. User speech converts locally via browser Web Speech API ──> POST webhook payload.\n2. The n8n Agent Node (Mistral Small) processes text while keeping memory in Postgres.\n3. If structural outputs match a specific string pattern, variables isolate into a custom data box before routing text back to the UI.\n\n## 🛠️ The 6 Agent Tools\n* **Users DB:** Handles structural SQL identity checks via session IDs and phone parameters.\n* **Serper:** Scrapes real-time search queries to generate context.\n* **Vector Ingest:** Pushes remote file clusters into processing vectors.\n* **Vector Query:** Fishes out specific indexed project links.\n* **Submit Short:** Fires short-form automated edits.\n* **Submit Post:** Fires full-scale platform distribution.\n\n---\n\n## 🚀 Setup Steps\n1. **Database:** Mount a Postgres or Supabase instance. Run a table create command for `users` featuring columns for `session_id`, `phone`, `email`, and `name`. Ensure a unique conflict constraint exists on the `phone` field.\n2. **Environment Variables:** Provide valid headers for your Mistral Cloud account, Serper search keys, and n8n webhook routing links.\n3. **Trigger:** Wire your frontend requests to the production path of your execution canvas node.\n4. **Front end Web UI** index file avail in part from us dev@w57th.agency.\n5. **Endpoint Variables:** Update the hardcoded `https://YOUR WORKFLOW/webhook/...` placeholders in the Vector Ingest, Vector Query, Submit Post, and Submit Short HTTP tool nodes to match your live production instance domain.",
        "height": 624,
        "width": 720,
        "color": "#F7F5B5"
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1456,
        928
      ],
      "typeVersion": 1,
      "id": "d44313ae-12ae-4c5a-8f83-ed8293fbf534",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "sessionIdType": "customKey",
        "sessionKey": "={{ $json.body.sessionId }}",
        "contextWindowLength": 20
      },
      "type": "@n8n/n8n-nodes-langchain.memoryPostgresChat",
      "typeVersion": 1.3,
      "position": [
        -432,
        704
      ],
      "id": "145ac923-accf-4f37-a311-12efd0c69655",
      "name": "Chat History",
      "credentials": {
        "postgres": {
          "id": "xu6lcWFSTh9cU4FG",
          "name": "w57th db"
        }
      }
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "Sorry, there's an error in the n-8-n AI Agent node.",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        304,
        544
      ],
      "id": "5908b10d-8fb2-466b-9bf2-5b4214c7b334",
      "name": "Error Mssg"
    },
    {
      "parameters": {
        "content": "# Fred Voice AI Web App\n## 🎙️Web User STT -> n8n LLM -> Web Grok TTS",
        "height": 688,
        "width": 1408,
        "color": "#2A2A3C"
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -736,
        288
      ],
      "typeVersion": 1,
      "id": "b72b135d-dfba-461f-9dad-5145cf5479a8",
      "name": "Sticky Note2"
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "={{ $json.output }}",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        192,
        432
      ],
      "id": "d4ec4d5b-e401-47fe-9fc3-86df7bba2fab",
      "name": "To Chat UI"
    },
    {
      "parameters": {
        "toolDescription": "Call to post Users media folder to Vector Ingest sub-flow\nFields:\n0 bucket\n1 folder_url",
        "method": "POST",
        "url": "https://YOUR WORKFLOW/webhook/vector-ingest",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "bucket",
              "value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters0_Value', `bucket`, 'string') }}"
            },
            {
              "name": "folder_url",
              "value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters1_Value', `folder_url`, 'string') }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequestTool",
      "typeVersion": 4.4,
      "position": [
        -96,
        704
      ],
      "id": "bcb03a91-6ea6-41f9-b1d3-c00ba444a401",
      "name": "Vector Ingest"
    },
    {
      "parameters": {
        "toolDescription": "Call to post query to Vector Query to retrieve User media",
        "method": "POST",
        "url": "https://YOUR WORKFLOW/webhook/vector-query",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "query",
              "value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters0_Value', `query`, 'string') }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequestTool",
      "typeVersion": 4.4,
      "position": [
        32,
        704
      ],
      "id": "dde54f79-5552-412f-a219-8aa6ca593ec7",
      "name": "Vector Query"
    },
    {
      "parameters": {
        "toolDescription": "Call to Submit Post.\nSubmits a post to the content factory.\n\nFields: \n0 Topic (required), \n1 Content, \n2 Mentions, \n3 Hashtags, \n4 Urls, \n5 Media, \n6 phone (required, valid phone, from Users DB), \n7 email (may be null).",
        "method": "POST",
        "url": "https://YOUR WORKFLOW/webhook/post",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "Topic",
              "value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters0_Value', `Topic`, 'string') }}"
            },
            {
              "name": "Content",
              "value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters1_Value', `Content`, 'string') }}"
            },
            {
              "name": "Mentions",
              "value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters2_Value', `Mentions`, 'string') }}"
            },
            {
              "name": "Hashtags",
              "value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters3_Value', `Hashtags`, 'string') }}"
            },
            {
              "name": "Urls",
              "value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters4_Value', `Urls`, 'string') }}"
            },
            {
              "name": "Media",
              "value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters5_Value', `Media`, 'string') }}"
            },
            {
              "name": "phone",
              "value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters6_Value', `phone`, 'string') }}"
            },
            {
              "name": "email",
              "value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters7_Value', `email`, 'string') }}"
            },
            {
              "name": "submittedAt",
              "value": "={{ $now }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequestTool",
      "typeVersion": 4.4,
      "position": [
        256,
        704
      ],
      "id": "393c20ff-01c0-4df0-8171-92be1cc5a122",
      "name": "Submit Post"
    },
    {
      "parameters": {
        "content": "# 🌐 The Front-End Engine (`index.html` + `style.css`)\n\n## ⚡ Hosting & CI/CD Pipeline\n* **Infrastructure:** Zero-server, 100% static asset deployment hosted natively on Cloudflare Pages.\n* **Deployment:** Linked directly to your code repository. Any main-branch git commit instantly triggers an automated cloud rebuild.\n\n## 🎙️ High-Speed Voice Translation\n* **STT (Speech-to-Text):** Runs entirely inside the local window using the native browser Web Speech API. Bypasses transcription server lags for near-instant execution.\n* **TTS (Text-to-Speech):** Accepts incoming execution audio links directly from Grok TTS. If stream drops, it uses an internal browser speech fallback.\n\n## 🔐 Local Session Identity\n* Uses standard browser storage arrays to maintain user persistence.\n* Generates a permanent `sessionId` inside `localStorage` on initial boot, wrapping it into every webhook post body so your agent always knows exactly who is speaking.\n\n## 📺 Dynamic Media Display Box\n* **The Parser:** Intercepts incoming responses. If text starts with `\"Media query results received:\"`, it automatically strips the raw URLs from the text string so the voice engine never awkwardly reads them out loud.\n* **The Viewer Grid:** Converts those extracted links into a visual layout directly inside the scroll window. It clusters video frames together, opens images full-size upon a user click, streams native mp4 video controls, and links out PDFs automatically.",
        "height": 688,
        "width": 608,
        "color": "#2E2E2E"
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        672,
        288
      ],
      "typeVersion": 1,
      "id": "ad485333-4711-4d69-af36-b43aa4381bcc",
      "name": "Sticky Note4"
    },
    {
      "parameters": {
        "toolDescription": "Call to Submit Short",
        "method": "POST",
        "url": "https://YOUR WORKFLOW/webhook/short",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "public_url",
              "value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters0_Value', `public_url`, 'string') }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequestTool",
      "typeVersion": 4.4,
      "position": [
        144,
        704
      ],
      "id": "c1190951-d009-47f6-b83b-3273acbebb4c",
      "name": "Submit Short"
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Read or write to the postgres users table.\n\nTable columns: id, session_id, phone, email, name, first_login, last_login, posts, last_execution_id\n\nTo upsert a user (Target conflict on phone to merge multi-device sessions):\nINSERT INTO users (session_id, name, phone, email)\nVALUES ('abc123', 'Dave', '16468010140', 'dave@gmail.com')\nON CONFLICT (phone) DO UPDATE SET\n  session_id = EXCLUDED.session_id,\n  name = COALESCE(EXCLUDED.name, users.name),\n  email = COALESCE(EXCLUDED.email, users.email);\n\nTo read a user by session_id:\nSELECT * FROM users WHERE session_id = 'abc123';\n\nTo read a user by phone:\nSELECT * FROM users WHERE phone = '16468010140';\n\nRules: Use NULL (unquoted) for missing fields. Use single quotes around all string values.",
        "operation": "executeQuery",
        "query": "{{ $fromAI('query') }}",
        "options": {}
      },
      "type": "n8n-nodes-base.postgresTool",
      "typeVersion": 2.6,
      "position": [
        -320,
        704
      ],
      "id": "76b57426-25df-46a7-9bc7-e1f20d32d65b",
      "name": "Users DB",
      "credentials": {
        "postgres": {
          "id": "xu6lcWFSTh9cU4FG",
          "name": "w57th db"
        }
      }
    },
    {
      "parameters": {
        "content": "# 🎙️ Fred Voice AI — Tldr\n\n## 🕶️ Identity Profile\nImagine a retired, 1980s Madison Avenue ad-man who had his soul trapped inside a Cloudflare front-end file. Fred has dry wit, a bad attitude, and zero tolerance for sloppy workflows. He speaks with sharp, punchy cadence via **Grok TTS** (or native browser audio fallbacks). He knows your backend is a massive automated beast, and acts as its gatekeeper.\n\n## 📱 Omnipresent Interfaces\n* **Web UI Mode:** Real-time browser voice-in/voice-out via a raw HTML file.\n* **WhatsApp Mode:** A secondary text/audio channel running on the exact same cross-device user database.\n\n## 🗄️ Memory & Asset Manipulation\n* **Vector Overlord:** He can swallow an entire directory of PDFs, images, or raw video links via the Ingest tool, or instantly run semantic metadata queries to fish out exact assets.\n* **Ideation Partner:** Calls live Google Search parameters via Serper to map out media trends and build content ideas.\n\n## 🏭 Pipeline Triggers\n* **Tool 1: Submit Post:** Passes your structured briefs directly to the W57th master system. It spins up a custom 20-second background track, matches an AI visual, renders text overlays, and organically prints to 6 social networks.\n* **Tool 2: Submit Short:** For your raw, rough-cut reels. He forwards the link to the video editor microservice to add punch captions, render dynamic thumbnails, tag handles, insert descriptions, and drop it across the exact same 6 social networks.",
        "height": 608,
        "width": 720,
        "color": "#F7F5B5"
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1456,
        288
      ],
      "typeVersion": 1,
      "id": "dc2ada26-c857-4d99-95fd-fa84ade0eafc",
      "name": "Sticky Note7"
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-4o-mini",
          "mode": "list",
          "cachedResultName": "gpt-4o-mini"
        },
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        -80,
        1952
      ],
      "id": "86eb400a-491f-4ec0-9b59-b6766dd1561a",
      "name": "OpenAI Chat Model",
      "credentials": {
        "openAiApi": {
          "id": "XI6quB65udB3rz2M",
          "name": "ChatGPT"
        }
      },
      "disabled": true
    }
  ],
  "pinData": {},
  "connections": {
    "Serper": {
      "ai_tool": [
        [
          {
            "node": "Fred",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Fred": {
      "main": [
        [
          {
            "node": "To Chat UI",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Error Mssg",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mistral Cloud Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Fred",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Fred Hook": {
      "main": [
        [
          {
            "node": "Fred",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Chat History": {
      "ai_memory": [
        [
          {
            "node": "Fred",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Vector Ingest": {
      "ai_tool": [
        [
          {
            "node": "Fred",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Vector Query": {
      "ai_tool": [
        [
          {
            "node": "Fred",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Submit Post": {
      "ai_tool": [
        [
          {
            "node": "Fred",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Submit Short": {
      "ai_tool": [
        [
          {
            "node": "Fred",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Users DB": {
      "ai_tool": [
        [
          {
            "node": "Fred",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        []
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate",
    "timeSavedMode": "fixed",
    "callerPolicy": "workflowsFromSameOwner",
    "availableInMCP": false
  },
  "versionId": "cb2b6002-69b2-458c-9f07-5337dbe4ec2e",
  "meta": {
    "templateCredsSetupCompleted": true,
    "aiBuilderAssisted": true,
    "builderVariant": "mcp",
    "instanceId": "f65635fe42aeebebf44eaa521e38cac56bb6b5ccb60db8ca4a763a8fbba06ee8"
  },
  "nodeGroups": [],
  "id": "yk1mUHGXis9cUqoS",
  "tags": []
}