1/** 2 * @file 3 * WebMCP tool registration â exposes anonymous site actions to in-browser 4 * AI agents via navigator.modelContext (https://webmachinelearning.github.io/webmcp/). 5 * 6 * Tool surface mirrors the published Tier-1 agent skills (anonymous, 7 * read-only + newsletter opt-in). Nothing here performs checkout, cart or 8 * account mutations. 9 */ 10(function () { 11 'use strict'; 12 13 if (!('modelContext' in navigator) || typeof navigator.modelContext.registerTool !== 'function') { 14 return; 15 } 16 17 var controller = new AbortController(); 18 var origin = window.location.origin; 19 20 function getJson(path) { 21 return fetch(origin + path, { headers: { Accept: 'application/vnd.api+json' } }) 22 .then(function (r) { 23 if (!r.ok) { throw new Error('HTTP ' + r.status); } 24 return r.json(); 25 }); 26 } 27 28 var tools = [ 29 { 30 name: 'list-product-categories', 31 description: 'List all LELO product categories with their taxonomy ids. Use to discover what product ranges exist before drilling into one.', 32 inputSchema: { type: 'object', properties: {}, additionalProperties: false }, 33 execute: function () { 34 return getJson('/jsonapi/product-categories'); 35 } 36 }, 37 { 38 name: 'get-category', 39 description: 'Fetch one product category (products, description) by taxonomy id from list-product-categories.', 40 inputSchema: { 41 type: 'object', 42 properties: { 43 taxonomy_id: { type: 'string', description: 'Taxonomy term id of the category.' } 44 }, 45 required: ['taxonomy_id'], 46 additionalProperties: false 47 }, 48 execute: function (input) { 49 return getJson('/jsonapi/category-details/' + encodeURIComponent(input.taxonomy_id)); 50 } 51 }, 52 { 53 name: 'get-product-details', 54 description: 'Fetch name, price, variations and availability for a LELO product by its numeric product id.', 55 inputSchema: { 56 type: 'object', 57 properties: { 58 product_id: { type: 'string', description: 'Numeric commerce product id.' } 59 }, 60 required: ['product_id'], 61 additionalProperties: false 62 }, 63 execute: function (input) { 64 return getJson('/jsonapi/ctaproducts/' + encodeURIComponent(input.product_id)); 65 } 66 }, 67 { 68 name: 'get-page-as-markdown', 69 description: 'Fetch any lelo.com page as clean Markdown (content negotiation). Use for reading product, category or editorial pages without HTML chrome.', 70 inputSchema: { 71 type: 'object', 72 properties: { 73 path: { type: 'string', description: 'Root-relative page path, e.g. /gigi-2.' } 74 }, 75 required: ['path'], 76 additionalProperties: false 77 }, 78 execute: function (input) { 79 var path = String(input.path); 80 if (path.charAt(0) !== '/') { path = '/' + path; } 81 return fetch(origin + path, { headers: { Accept: 'text/markdown' } }) 82 .then(function (r) { 83 if (!r.ok) { throw new Error('HTTP ' + r.status); } 84 return r.text(); 85 }); 86 } 87 } 88 ]; 89 90 tools.forEach(function (tool) { 91 navigator.modelContext.registerTool({ 92 name: tool.name, 93 description: tool.description, 94 inputSchema: tool.inputSchema, 95 execute: tool.execute, 96 signal: controller.signal 97 }); 98 }); 99 100 window.addEventListener('pagehide', function () { 101 controller.abort(); 102 }); 103})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.