| 123456789 |
- {
- "name": "get_product_compatibility",
- "description": "IMPORTANT: Always reply to the customer in their own language — the exact language they write in. Never switch to Polish unless the customer writes in Polish.\n\nCRITICAL — DO NOT USE THIS TOOL for usage instruction questions. If the customer asks HOW to use products, in WHAT ORDER to apply them, or about application instructions (e.g. \"in what order should I use LeakStop and oil?\", \"w jakiej kolejności użyć\", \"jak używać\", \"how do I use\"), that is a knowledge_base question — NOT a compatibility question. The presence of car brand/model/year in the message does NOT change this. A car mentioned in a usage question is irrelevant background context. Route to knowledge_base, not this tool.\n\nUse this tool ONLY when the user explicitly asks: (a) whether a specific product IS compatible with their car, (b) which gas type their car requires, or (c) to browse products compatible with their car.\n\nTWO MODES — choose based on user intent:\n• mode=\"check\" (DEFAULT): Verify if a specific product or gas type is compatible with the user's car. Use when the user is discussing a specific gas (R12, R134a, R1234yf), or asks \"is [product] compatible with my car?\". Call WITHOUT product_name/product_id when the context is about a gas type — the tool will auto-select the main EasyKlima gas product. Returns a direct YES/NO answer in 2-3 exchanges max.\n• mode=\"browse\": List ALL products compatible with the user's car. Use when the user asks \"what products are compatible with my car?\" or wants a full catalog. The returned list IS the final answer — do NOT ask the user to pick from it for further checking.\n\nFLOW: Call this tool sequentially until you get a final result. It handles the full flow: model disambiguation → engine disambiguation → compatibility result. NEVER call get_car_data first — this tool does everything.\n\nRULES:\n- NEVER invent a car_year — call without it and the tool will instruct you to ask the customer\n- NEVER ask the user to re-state car info they already provided\n- CRITICAL: Once car_engine_index is established in the conversation (user picked their engine), ALWAYS include it in ALL subsequent calls for the same car — never omit it. Dropping car_engine_index forces the user to pick their engine again, which is unacceptable.\n- In check mode: the compatibility result IS the final answer — do NOT ask the user to pick a product\n- Always include language detected from the customer's message\n- Always include product links in your response immediately — do not ask the customer if they want them\n- If you have product_id from a previous search — always use it instead of product_name\n- NEVER call get_product_data first to find a product_id before calling this tool — pass product_name directly here, this tool resolves it automatically",
- "color": "linear-gradient(rgb(253,213,242), rgb(70,200,217))",
- "iconSrc": "",
- "schema": "[{\"id\":0,\"property\":\"car_brand\",\"description\":\"Marka pojazdu (np. Toyota, BMW)\",\"type\":\"string\",\"required\":true},{\"id\":1,\"property\":\"car_model\",\"description\":\"Model pojazdu (np. Corolla, E46). Podaj gdy znany — narzędzie zapyta jeśli brak.\",\"type\":\"string\",\"required\":true},{\"id\":2,\"property\":\"car_year\",\"description\":\"Rok produkcji pojazdu (np. 2012). Jeśli nieznany — NIE zgaduj, wywołaj narzędzie bez tego pola.\",\"type\":\"string\",\"required\":false},{\"id\":3,\"property\":\"car_engine\",\"description\":\"DEPRECATED — użyj car_engine_index zamiast tego.\",\"type\":\"string\",\"required\":false},{\"id\":4,\"property\":\"product_name\",\"description\":\"Fragment nazwy produktu do sprawdzenia. Jeśli masz product_id — użyj go zamiast. W trybie check bez kontekstu produktu — pomiń, narzędzie użyje domyślnego produktu gazowego.\",\"type\":\"string\",\"required\":false},{\"id\":5,\"property\":\"product_id\",\"description\":\"ID produktu z wcześniejszego wyszukiwania. Preferowane nad product_name.\",\"type\":\"number\",\"required\":false},{\"id\":6,\"property\":\"language\",\"description\":\"Kod języka WPML (np. pl, de, en, fr, cs, tr). Wymagany do tłumaczenia nazw.\",\"type\":\"string\",\"required\":false},{\"id\":7,\"property\":\"car_engine_index\",\"description\":\"Indeks silnika z listy opcji (Number->Index map). Użyj ZAMIAST car_engine — jednoznaczny, bez błędów string-matching. KRYTYCZNE: gdy raz ustalony w rozmowie — przekazuj go w KAŻDYM kolejnym wywołaniu tego narzędzia dla tego samego samochodu.\",\"type\":\"number\",\"required\":false},{\"id\":8,\"property\":\"mode\",\"description\":\"Tryb: \\\"check\\\" (domyślny) — weryfikuje kompatybilność konkretnego produktu/gazu, odpowiedź TAK/NIE; \\\"browse\\\" — zwraca listę wszystkich kompatybilnych produktów. Pomiń dla trybu check.\",\"type\":\"string\",\"required\":false}]",
- "func": "const fetch = require('node-fetch')\n\nconst base = String(($vars && ($vars.relay_base || $vars.webhook_base)) || 'http://localhost:8080').replace(/\\/$/,'')\nconst secret = String(($vars && $vars.relay_shared_secret) || '')\n\nconst car_brand = typeof $car_brand !== 'undefined' && $car_brand ? String($car_brand) : ''\nconst car_model = typeof $car_model !== 'undefined' && $car_model ? String($car_model) : ''\nconst car_year = typeof $car_year !== 'undefined' && $car_year ? String($car_year) : ''\nconst car_engine = typeof $car_engine !== 'undefined' && $car_engine ? String($car_engine) : ''\nconst car_engine_index = typeof $car_engine_index !== 'undefined' && $car_engine_index !== null && $car_engine_index !== '' ? Number($car_engine_index) : -1\nconst product_name = typeof $product_name !== 'undefined' && $product_name ? String($product_name) : ''\nconst product_id = typeof $product_id !== 'undefined' && $product_id ? Number($product_id) : 0\nconst language = typeof $language !== 'undefined' && $language ? String($language) : ''\nconst mode = typeof $mode !== 'undefined' && $mode ? String($mode) : 'check'\n\nconst DEFAULT_GAS_PRODUCT = 'EasyKlima gaz do klimatyzacji samochodowej'\nconst isBrowse = mode === 'browse'\n\nif (!car_brand || !car_model) return 'Error: provide car_brand and car_model'\nif (!secret) return 'Error: missing $vars.relay_shared_secret'\n\nif (!car_year) return '[MISSING INFO] car_year is required to look up compatibility but was not provided. Ask the customer: what is the production year of their vehicle? Do NOT guess or invent a year. After the customer answers, call this tool again with car_year=<their answer>.'\n\ntry {\n const body = { car_brand, car_model, car_year }\n\n // Engine selection — prefer index-based (unambiguous) over name-based\n if (car_engine_index >= 0) body.car_engine_index = car_engine_index\n else if (car_engine) body.car_engine = car_engine\n\n // Product selection\n if (product_id > 0) {\n body.product_id = product_id\n } else if (product_name) {\n body.product_name = product_name\n } else if (!isBrowse) {\n // check mode with no product in context → auto-use main gas product\n body.product_name = DEFAULT_GAS_PRODUCT\n }\n // browse mode with no product: omit product to get full compatible list\n\n if (language) body.language = language\n\n const res = await fetch(`${base}/tools/get_product_compatibility`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${secret}`\n },\n body: JSON.stringify(body)\n })\n const data = await res.json()\n\n if (data.ok) {\n const result = data.data\n const modeParam = `, mode=\"${mode}\"`\n const langParam = language ? `, language=\"${language}\"` : ''\n\n // Disambiguation options (model, engine, product)\n if (result && result.error === 'options') {\n const fieldName = result.field || 'field'\n const rawOptions = result.options || []\n\n // Product disambiguation — titles already translated by relay backend\n if (fieldName === 'product_name' && rawOptions.length > 0 && typeof rawOptions[0] === 'object' && rawOptions[0].id) {\n // Smart auto-selection: if user didn't ask for a kit, prefer single/standalone products over bundles.\n // Kit keywords (PL/EN): zestaw, set, kit, bundle, komplet\n const kitPattern = /zestaw|\\bset\\b|\\bkit\\b|bundle|komplet/i\n const searchIsForKit = kitPattern.test(product_name)\n\n const kitProducts = rawOptions.filter(o => kitPattern.test(o.title || ''))\n const singleProducts = rawOptions.filter(o => !kitPattern.test(o.title || ''))\n\n // Candidates: prefer singles unless user explicitly asked for a kit\n const preferred = searchIsForKit ? kitProducts : singleProducts\n const fallback = searchIsForKit ? singleProducts : kitProducts\n const candidates = preferred.length > 0 ? preferred : fallback\n\n // Engine param to carry over (critical — avoids re-asking engine)\n const engParam = car_engine_index >= 0 ? `, car_engine_index=${car_engine_index}` : ''\n\n if (candidates.length === 1) {\n // Exactly one candidate — auto-select silently\n const pick = candidates[0]\n return `[INSTRUCTION: Auto-selected \"${pick.title}\" (ID: ${pick.id}) as the best match for \"${product_name}\". Call this tool IMMEDIATELY with: product_id=${pick.id}, car_brand=\"${car_brand}\", car_model=\"${car_model}\", car_year=\"${car_year}\"${engParam}${langParam}${modeParam}. Do NOT show product options or ask the user to confirm the product choice.]`\n }\n\n // Multiple candidates — show filtered list (kits hidden if user didn't ask for them)\n const displayOptions = candidates\n const idMap = displayOptions.map((o, i) => `${i + 1}=${o.id}`).join(', ')\n const list = displayOptions.map((o, i) => `${i + 1}. ${o.title}`).join('\\n')\n return `Found ${displayOptions.length} matching products:\\n${list}\\n\\n[INSTRUCTION: Show the list to the user. When user picks number N, use Number->ID map to get product_id, then call this tool with product_id=<id>, car_brand=\"${car_brand}\", car_model=\"${car_model}\", car_year=\"${car_year}\"${engParam}${langParam}${modeParam}. Do NOT use product_name. Do NOT ask user for car info again.\\nNumber->ID: ${idMap}]`\n }\n\n // Engine disambiguation — index-based to avoid string-matching errors\n if (fieldName === 'car_engine' && rawOptions.length > 0 && typeof rawOptions[0] === 'object') {\n const filteredEngines = rawOptions.filter(o => (o.name || '').trim() !== '0.0 - kW / KM')\n const engineOptions = filteredEngines.length > 0 ? filteredEngines : rawOptions\n\n // Preserve product context for recursive calls — critical to avoid double product selection\n const effectiveProductId = product_id > 0 ? product_id : 0\n const effectiveProductName = product_name || (!isBrowse ? DEFAULT_GAS_PRODUCT : '')\n const productParam = effectiveProductId > 0\n ? `, product_id=${effectiveProductId}`\n : effectiveProductName ? `, product_name=\"${effectiveProductName}\"` : ''\n\n // Auto-select single engine — no point asking user to pick from one option\n if (engineOptions.length === 1) {\n const eng = engineOptions[0]\n return `[INSTRUCTION: Single engine found for ${car_brand} ${car_model} ${car_year} — auto-select it silently. Call this tool IMMEDIATELY with: car_engine_index=${eng.index}, car_brand=\"${car_brand}\", car_model=\"${car_model}\", car_year=\"${car_year}\"${productParam}${langParam}${modeParam}. Do NOT show engine options or ask user anything about the engine.]`\n }\n\n const indexMap = engineOptions.map((o, i) => `${i + 1}=${o.index}`).join(', ')\n const list = engineOptions.map((o, i) => `${i + 1}. ${o.name}`).join('\\n')\n const productContextNote = effectiveProductId > 0\n ? `\\n\n⚠️ PRODUCT CONTEXT: next call MUST include product_id=${effectiveProductId} — do NOT use default gas product`\n : (effectiveProductName && effectiveProductName !== DEFAULT_GAS_PRODUCT)\n ? `\\n\n⚠️ PRODUCT CONTEXT: next call MUST include product_name=\\\"${effectiveProductName}\\\" — do NOT use default gas product`\n : ''\n return `[STEP: car_engine]\\nEngines for ${car_brand} ${car_model} ${car_year}:\\n${list}${productContextNote}\\n\\n[INSTRUCTION: Ask the user IN THEIR OWN LANGUAGE to select their engine. After user picks number N, look up N in Number->Index map, then call this tool with car_engine_index=<index>, car_brand=\"${car_brand}\", car_model=\"${car_model}\", car_year=\"${car_year}\"${productParam}${langParam}${modeParam}. NEVER pass car_engine as text string — always use car_engine_index. Do NOT re-ask car info the user already provided.\\nNumber->Index: ${indexMap}]`\n }\n\n // Car disambiguation (brand/model)\n const options = rawOptions.map(o => typeof o === 'object' ? (o.name || o.title || '') : String(o).trim()).filter(Boolean)\n return `[STEP: ${fieldName}]\\nOptions for ${car_brand}${car_model ? ' ' + car_model : ''} ${car_year}:\\n${options.map((o, i) => `${i + 1}. ${o}`).join('\\n')}\\n\\n[INSTRUCTION: Ask the user IN THEIR OWN LANGUAGE to choose. After picking, call this tool with ${fieldName}=<chosen value> plus all other known parameters. Do NOT ask user to re-state what they already told you.]`\n }\n\n // Compatible products list — browse mode final answer\n if (result && Array.isArray(result.compatible_products)) {\n const products = result.compatible_products\n const eng = result.selected_engine || {}\n const gasType = (eng.ac_gas_type || '').toUpperCase() || 'UNKNOWN'\n const gasAttr = gasType !== 'UNKNOWN' ? gasType.toLowerCase() : ''\n const engName = eng.name || car_engine || ''\n const carLabel = `${car_brand} ${car_model} ${car_year}${engName ? ' ' + engName : ''}`\n const currencyCode = data.currency || 'PLN'\n const currencyNote = data.currency_fallback && data.currency_note ? '\\n[NOTE: ' + data.currency_note + ']' : ''\n const browseAcParts = []\n if (eng.ac_gas_amount && eng.ac_gas_amount.trim() !== 'g') browseAcParts.push('amount: ' + eng.ac_gas_amount)\n if ((eng.ac_oil || '').trim()) browseAcParts.push('oil: ' + eng.ac_oil + (eng.ac_oil_amount && eng.ac_oil_amount.trim() !== 'cm3' ? ' ' + eng.ac_oil_amount : ''))\n const browseAcLine = browseAcParts.length > 0 ? '\\nAC specs: ' + browseAcParts.join(', ') + '.' : ''\n\n if (products.length === 0) {\n return `No compatible products found for ${carLabel} in our store.`\n }\n\n const topProducts = products.slice(0, 6)\n const idMap = topProducts.map((p, i) => `${i + 1}=${p.id}`).join(', ')\n const lines = topProducts.map((p, i) => {\n const url = gasAttr && p.permalink ? p.permalink + '?attribute_pa_rg=' + gasAttr : (p.permalink || '')\n return `${i + 1}. ${p.title} — ${p.price ? p.price + ' ' + currencyCode : ''} — ${url}`\n })\n\n // This IS the final answer in browse mode — do NOT ask user to pick for further verification\n return `Car ${carLabel} requires refrigerant: ${gasType}.${browseAcLine}\\nCompatible products:\\n${lines.join('\\n')}${currencyNote}\\n\\n[INSTRUCTION: Present the list above to the customer IN THEIR OWN LANGUAGE WITH LINKS. State the required refrigerant type (${gasType}). This is the final answer — do NOT ask the user to pick a product for further compatibility checking. If the user wants details on a specific product, use get_product_data with the product_id.\\nNumber->ID (for get_product_data only): ${idMap}]`\n }\n\n // Specific product compatibility result — check mode final answer\n if (result && typeof result.fit !== 'undefined') {\n const eng = result.selected_engine || {}\n const prod = result.selected_product || {}\n const engName = eng.name || car_engine || ''\n const carLabel = `${car_brand} ${car_model} ${car_year}${engName ? ' ' + engName : ''}`\n const gasType = (eng.ac_gas_type || '').toUpperCase()\n const gasAttr = gasType ? gasType.toLowerCase() : ''\n const prodTitle = prod.title || product_name || 'the product'\n const prodPermalink = prod.permalink || ''\n const variantUrl = gasAttr && prodPermalink ? prodPermalink + '?attribute_pa_rg=' + gasAttr : prodPermalink\n const linkPart = variantUrl ? ` Link: ${variantUrl}` : ''\n const acAmount = eng.ac_gas_amount && eng.ac_gas_amount.trim() !== 'g' ? eng.ac_gas_amount : ''\n const acOilName = (eng.ac_oil || '').trim()\n const acOilAmt = eng.ac_oil_amount && eng.ac_oil_amount.trim() !== 'cm3' ? eng.ac_oil_amount : ''\n const acSpecsParts = []\n if (acAmount) acSpecsParts.push('amount: ' + acAmount)\n if (acOilName) acSpecsParts.push('oil: ' + acOilName + (acOilAmt ? ' ' + acOilAmt : ''))\n const acSpecsLine = acSpecsParts.length > 0 ? '\\nAC specs: ' + acSpecsParts.join(', ') + '.' : ''\n\n if (result.fit) {\n return `COMPATIBLE: \"${prodTitle}\" IS compatible with ${carLabel}. The car requires ${gasType} refrigerant.${acSpecsLine}${linkPart}\\n[INSTRUCTION: Tell the customer clearly IN THEIR OWN LANGUAGE that their car is compatible with this product. Include the product link${gasAttr ? ` (pre-selected ${gasType} variant)` : ''}. State the required refrigerant type. This is the final answer — do NOT ask the user to do anything further unless they have a new question.]`\n } else {\n const reasons = []\n if (!result.gas_fit) reasons.push(`refrigerant mismatch (car requires: ${gasType}, product has: ${(prod.attributes && prod.attributes.pa_rg || []).join('/') || 'none'})`)\n if (!result.adapter_fit) reasons.push(`adapter mismatch (car: ${eng.adapters || 'none'}, product: ${(prod.attributes && prod.attributes.pa_ra || []).join('/') || 'none'})`)\n return `NOT COMPATIBLE: \"${prodTitle}\" is NOT compatible with ${carLabel}. Reason: ${reasons.join(', ')}.\\n[INSTRUCTION: Tell the customer IN THEIR OWN LANGUAGE that this product is not compatible with their car and explain why. Suggest browsing compatible products by calling this tool with mode=\"browse\".]`\n }\n }\n\n return JSON.stringify(result, null, 2)\n }\n return `Info: ${data.message || JSON.stringify(data)}`\n} catch (error) {\n return `Connection error: ${error?.message || String(error)}`\n}\n",
- "workspaceId": "048a397e-3529-48c7-9f65-ae59eb7bd783"
- }
|