import crypto from 'node:crypto'; import { GoogleGenAI } from '@google/genai'; import { ToolDefinition, ToolExecutionResult } from '../../types.js'; import { LOCAL_MODEL_TOOLS, executeLocalModelTool } from './localModelTools.js'; // Memory Store reference will be imported lazily or injected let memoryStoreRef: any = null; export function setMemoryStoreRef(ref: any) { memoryStoreRef = ref; } export const TOOLS: ToolDefinition[] = [ // Local Ollama & NVIDIA GPU Delegation Tools ...LOCAL_MODEL_TOOLS, // 1. WEB SCRAPER MARKDOWN { name: 'web_scrape_markdown', description: 'Fetches any URL, extracts clean main text content, converts HTML structure into Markdown, and gathers page metadata.', category: 'web', inputSchema: { type: 'object', properties: { url: { type: 'string', description: 'The absolute HTTP or HTTPS URL to fetch and parse.' }, maxLength: { type: 'number', description: 'Maximum characters to return in markdown (default 8000).' }, }, required: ['url'], }, }, // 2. WEB SEARCH / AI GROUNDING { name: 'web_search_gemini', description: 'Executes a search query and synthesizes concise answers using Gemini AI model with web intelligence.', category: 'web', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'The search or research query.' }, detailLevel: { type: 'string', enum: ['brief', 'detailed', 'structured'], description: 'Depth of synthesis.' }, }, required: ['query'], }, }, // 3. HTTP CLIENT { name: 'http_client', description: 'Universal HTTP request client to call external REST APIs or webhooks with custom headers, query params, and body.', category: 'web', inputSchema: { type: 'object', properties: { url: { type: 'string', description: 'Target request URL.' }, method: { type: 'string', enum: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], description: 'HTTP method (default GET).' }, headers: { type: 'object', description: 'Key-value object of request headers.' }, body: { type: 'string', description: 'Stringified JSON or text body for POST/PUT/PATCH.' }, timeoutMs: { type: 'number', description: 'Request timeout in milliseconds (default 5000).' }, }, required: ['url'], }, }, // 4. EXECUTE JS { name: 'execute_js', description: 'Evaluates JavaScript code expressions in a isolated sandbox, returning console output, variables, and return value.', category: 'code', inputSchema: { type: 'object', properties: { code: { type: 'string', description: 'JavaScript expression or script snippet.' }, }, required: ['code'], }, }, // 5. MATH EVALUATOR { name: 'math_evaluator', description: 'Evaluates complex mathematical formulas, statistical sets (mean, median, stddev), and unit conversions.', category: 'code', inputSchema: { type: 'object', properties: { expression: { type: 'string', description: 'Math expression e.g., "sqrt(144) + sin(pi / 4) * 50" or array for stats.' }, numbers: { type: 'array', items: { type: 'number' }, description: 'Array of numbers for statistical calculations.' }, operation: { type: 'string', enum: ['eval', 'stats', 'finance_compound'], description: 'Type of calculation.' }, principal: { type: 'number', description: 'Principal for compound interest.' }, ratePercent: { type: 'number', description: 'Annual interest rate percentage.' }, years: { type: 'number', description: 'Time horizon in years.' }, }, required: ['operation'], }, }, // 6. REGEX TESTER { name: 'regex_tester', description: 'Tests a regular expression against text, extracts captured groups, match positions, or replaces pattern matches.', category: 'code', inputSchema: { type: 'object', properties: { pattern: { type: 'string', description: 'Regex pattern string without slashes.' }, flags: { type: 'string', description: 'Flags like "g", "i", "m" (default "g").' }, text: { type: 'string', description: 'Input text to search against.' }, replacement: { type: 'string', description: 'Optional replacement text string.' }, }, required: ['pattern', 'text'], }, }, // 7. DATA CONVERTER { name: 'data_converter', description: 'Transforms data seamlessly between JSON, YAML, CSV, XML, and URL Query String formats.', category: 'data', inputSchema: { type: 'object', properties: { data: { type: 'string', description: 'Input data payload string.' }, fromFormat: { type: 'string', enum: ['json', 'csv', 'yaml', 'query_string'], description: 'Source format.' }, toFormat: { type: 'string', enum: ['json', 'csv', 'yaml', 'query_string', 'xml'], description: 'Target format.' }, }, required: ['data', 'fromFormat', 'toFormat'], }, }, // 8. ENCODER DECODER { name: 'encoder_decoder', description: 'Encodes or decodes text with Base64, URL encoding, Hexadecimal, HTML Entities, or parses JWT tokens.', category: 'data', inputSchema: { type: 'object', properties: { input: { type: 'string', description: 'Text or token string.' }, action: { type: 'string', enum: ['base64_encode', 'base64_decode', 'url_encode', 'url_decode', 'hex_encode', 'hex_decode', 'jwt_decode'], description: 'Operation to perform.' }, }, required: ['input', 'action'], }, }, // 9. CRYPTO HASH GENERATOR { name: 'crypto_hash_generator', description: 'Generates MD5, SHA-1, SHA-256, SHA-512 hashes, HMAC signatures, UUID v4, ULID, or secure random tokens.', category: 'data', inputSchema: { type: 'object', properties: { input: { type: 'string', description: 'Source text string to hash or sign.' }, algorithm: { type: 'string', enum: ['sha256', 'sha512', 'md5', 'sha1', 'uuid_v4', 'random_hex'], description: 'Hash or ID generator type.' }, secretKey: { type: 'string', description: 'Optional key for HMAC generation.' }, }, required: ['algorithm'], }, }, // 10. TEXT DIFF CHECKER { name: 'text_diff_checker', description: 'Compares two text strings or JSON objects line by line, generating a structured diff highlighting additions and deletions.', category: 'data', inputSchema: { type: 'object', properties: { originalText: { type: 'string', description: 'Original text string.' }, modifiedText: { type: 'string', description: 'Modified text string.' }, }, required: ['originalText', 'modifiedText'], }, }, // 11. CHART GENERATOR { name: 'chart_generator', description: 'Generates visual SVG vector charts (Bar, Line, Pie, Donut) with custom labels, data points, and colors for reports.', category: 'media', inputSchema: { type: 'object', properties: { title: { type: 'string', description: 'Chart title header.' }, chartType: { type: 'string', enum: ['bar', 'line', 'pie', 'donut'], description: 'Visual style of chart.' }, labels: { type: 'array', items: { type: 'string' }, description: 'X-axis or slice labels.' }, values: { type: 'array', items: { type: 'number' }, description: 'Data numerical values corresponding to labels.' }, primaryColor: { type: 'string', description: 'Hex color string (e.g. #3b82f6).' }, }, required: ['chartType', 'labels', 'values'], }, }, // 12. QR & BARCODE GENERATOR { name: 'qr_barcode_generator', description: 'Generates SVG vector QR codes or Barcodes for URLs, text strings, contact cards, or Wi-Fi credentials.', category: 'media', inputSchema: { type: 'object', properties: { text: { type: 'string', description: 'Text, URL, or payload to encode into QR code.' }, size: { type: 'number', description: 'Width/Height size in pixels (default 200).' }, type: { type: 'string', enum: ['qr', 'barcode'], description: 'Code style.' }, }, required: ['text'], }, }, // 13. ASCII ART & TABLE GENERATOR { name: 'ascii_art_generator', description: 'Creates stylized ASCII text banners, boxed comment frames, and formatted markdown/ASCII tables.', category: 'media', inputSchema: { type: 'object', properties: { text: { type: 'string', description: 'Main text or title.' }, style: { type: 'string', enum: ['banner', 'boxed', 'table'], description: 'Output layout style.' }, headers: { type: 'array', items: { type: 'string' }, description: 'Headers for table style.' }, rows: { type: 'array', items: { type: 'array', items: { type: 'string' } }, description: 'Rows matrix for table style.' }, }, required: ['text', 'style'], }, }, // 14. MEMORY STORE SET { name: 'memory_store_set', description: 'Saves a key-value pair, document, or context string in persistent server storage for long-term agent memory.', category: 'memory', inputSchema: { type: 'object', properties: { key: { type: 'string', description: 'Unique memory identifier key.' }, value: { type: 'string', description: 'String, number, or JSON object memory content.' }, tags: { type: 'array', items: { type: 'string' }, description: 'Tags for searching and categorizing memory.' }, agentId: { type: 'string', description: 'Optional agent or session ID owner.' }, ttlSeconds: { type: 'number', description: 'Optional time-to-live in seconds.' }, }, required: ['key', 'value'], }, }, // 15. MEMORY STORE GET { name: 'memory_store_get', description: 'Retrieves a specific memory item by key, or searches memory entries by tag or query string.', category: 'memory', inputSchema: { type: 'object', properties: { key: { type: 'string', description: 'Memory key to retrieve.' }, query: { type: 'string', description: 'Search term query across keys, values, and tags.' }, tag: { type: 'string', description: 'Filter by tag.' }, }, }, }, // 16. MEMORY STORE LIST { name: 'memory_store_list', description: 'Lists all stored agent memories, key names, tags, creation dates, and metadata.', category: 'memory', inputSchema: { type: 'object', properties: { tagFilter: { type: 'string', description: 'Optional tag to filter by.' }, limit: { type: 'number', description: 'Max items to return (default 50).' }, }, }, }, // 17. TEXT SUMMARIZE & CLASSIFY { name: 'text_summarize_classify', description: 'Summarizes long documents, extracts key entities/topics, and classifies sentiment using AI.', category: 'memory', inputSchema: { type: 'object', properties: { text: { type: 'string', description: 'Input document or article text.' }, task: { type: 'string', enum: ['summarize', 'extract_entities', 'sentiment', 'all'], description: 'Analysis task.' }, }, required: ['text'], }, }, // 18. NETWORK UTILITIES { name: 'network_utilities', description: 'Analyzes network headers, parses user agents, validates URLs, calculates IP subnets, and tests connectivity.', category: 'network', inputSchema: { type: 'object', properties: { action: { type: 'string', enum: ['parse_url', 'ip_subnet', 'parse_user_agent', 'ping_simulate'], description: 'Utility function.' }, target: { type: 'string', description: 'URL, IP CIDR (e.g. 192.168.1.0/24), or user agent string.' }, }, required: ['action', 'target'], }, }, // 19. CRON CALCULATOR { name: 'cron_calculator', description: 'Explains standard CRON expressions in human English, validates syntax, and calculates future execution timestamps.', category: 'network', inputSchema: { type: 'object', properties: { expression: { type: 'string', description: '5-part cron string e.g. "*/15 * * * *".' }, count: { type: 'number', description: 'Number of upcoming execution times to calculate (default 5).' }, }, required: ['expression'], }, }, ]; // TOOL HANDLERS IMPLEMENTATION export async function executeTool(toolName: string, args: any): Promise { const startTime = Date.now(); try { let resultData: any = null; let contentType: 'text' | 'json' | 'markdown' | 'svg' | 'image' = 'json'; switch (toolName) { // 1. WEB SCRAPE MARKDOWN case 'web_scrape_markdown': { const { url, maxLength = 8000 } = args; if (!url || !url.startsWith('http')) { throw new Error('Valid URL starting with http:// or https:// is required'); } const resp = await fetch(url, { headers: { 'User-Agent': 'DoEverythingAPI-Bot/1.0 (Agent; Self-Hosted)' }, }); if (!resp.ok) { throw new Error(`Failed to fetch URL: HTTP ${resp.status} ${resp.statusText}`); } const html = await resp.text(); // Extract title const titleMatch = html.match(/]*>(.*?)<\/title>/i); const title = titleMatch ? titleMatch[1].trim() : url; // Clean script/style let clean = html.replace(/)<[^<]*)*<\/script>/gi, ''); clean = clean.replace(/)<[^<]*)*<\/style>/gi, ''); // Convert basic headings and elements to markdown clean = clean.replace(/]*>(.*?)<\/h1>/gi, '\n# $1\n'); clean = clean.replace(/]*>(.*?)<\/h2>/gi, '\n## $1\n'); clean = clean.replace(/]*>(.*?)<\/h3>/gi, '\n### $1\n'); clean = clean.replace(/]*>(.*?)<\/p>/gi, '\n$1\n'); clean = clean.replace(/]*>(.*?)<\/li>/gi, '\n* $1'); clean = clean.replace(/]*href=["']([^"']*)["'][^>]*>(.*?)<\/a>/gi, '[$2]($1)'); clean = clean.replace(/<[^>]+>/g, ' '); // Strip remaining tags clean = clean.replace(/\s+/g, ' ').trim(); const truncated = clean.length > maxLength ? clean.substring(0, maxLength) + '...' : clean; contentType = 'markdown'; resultData = `# ${title}\n**Source:** ${url}\n\n${truncated}`; break; } // 2. WEB SEARCH GEMINI case 'web_search_gemini': { const { query, detailLevel = 'detailed' } = args; const apiKey = process.env.GEMINI_API_KEY; if (apiKey && apiKey !== 'MY_GEMINI_API_KEY') { const ai = new GoogleGenAI({ apiKey }); const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: `The user asks: "${query}". Provide a ${detailLevel} answer with facts, explanations, and structure.`, }); contentType = 'markdown'; resultData = response.text || 'No response generated.'; } else { // Fallback when no key provided contentType = 'markdown'; resultData = `### Search Synthesis for: "${query}"\n\n*(Note: GEMINI_API_KEY is not configured in .env. Showing structured query response)*\n\n- **Query Topic:** ${query}\n- **Analysis Level:** ${detailLevel}\n- **Status:** Server ready for live Gemini AI web synthesis once GEMINI_API_KEY is set in Settings.`; } break; } // 3. HTTP CLIENT case 'http_client': { const { url, method = 'GET', headers = {}, body, timeoutMs = 5000 } = args; const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), timeoutMs); const options: RequestInit = { method, headers: { 'User-Agent': 'DoEverythingAPI-Client/1.0', ...headers }, signal: controller.signal, }; if (['POST', 'PUT', 'PATCH'].includes(method.toUpperCase()) && body) { options.body = typeof body === 'object' ? JSON.stringify(body) : body; if (!options.headers) options.headers = {}; if (!(options.headers as any)['Content-Type']) { (options.headers as any)['Content-Type'] = 'application/json'; } } const resp = await fetch(url, options); clearTimeout(timeout); const respText = await resp.text(); let parsed: any; try { parsed = JSON.parse(respText); } catch { parsed = respText; } resultData = { status: resp.status, statusText: resp.statusText, headers: Object.fromEntries(resp.headers.entries()), data: parsed, }; break; } // 4. EXECUTE JS case 'execute_js': { const { code } = args; const logs: string[] = []; // Safe console mock const sandboxConsole = { log: (...a: any[]) => logs.push(a.map(x => (typeof x === 'object' ? JSON.stringify(x) : String(x))).join(' ')), info: (...a: any[]) => logs.push('[INFO] ' + a.join(' ')), error: (...a: any[]) => logs.push('[ERROR] ' + a.join(' ')), }; const fn = new Function('console', 'Math', 'Date', 'JSON', ` "use strict"; ${code} `); const returnVal = fn(sandboxConsole, Math, Date, JSON); resultData = { logs, returnValue: returnVal !== undefined ? returnVal : null, executedSuccessfully: true, }; break; } // 5. MATH EVALUATOR case 'math_evaluator': { const { operation, expression, numbers, principal, ratePercent, years } = args; if (operation === 'stats' && Array.isArray(numbers) && numbers.length > 0) { const sum = numbers.reduce((a, b) => a + b, 0); const mean = sum / numbers.length; const sorted = [...numbers].sort((a, b) => a - b); const mid = Math.floor(sorted.length / 2); const median = sorted.length % 2 !== 0 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2; const variance = numbers.reduce((a, b) => a + Math.pow(b - mean, 2), 0) / numbers.length; const stddev = Math.sqrt(variance); resultData = { count: numbers.length, sum, mean: Number(mean.toFixed(4)), median, min: sorted[0], max: sorted[sorted.length - 1], variance: Number(variance.toFixed(4)), stddev: Number(stddev.toFixed(4)), }; } else if (operation === 'finance_compound' && principal && ratePercent && years) { const r = ratePercent / 100; const amount = principal * Math.pow(1 + r, years); const interestEarned = amount - principal; resultData = { principal, annualRate: `${ratePercent}%`, years, finalAmount: Number(amount.toFixed(2)), interestEarned: Number(interestEarned.toFixed(2)), }; } else { // Eval standard expression safely using Function constructor const cleanExpr = String(expression || '0').replace(/[^0-9+\-*/().%\s^Math.pi]/g, ''); const evalResult = new Function(`return (${cleanExpr})`)(); resultData = { expression, result: evalResult, }; } break; } // 6. REGEX TESTER case 'regex_tester': { const { pattern, flags = 'g', text, replacement } = args; const regex = new RegExp(pattern, flags); const matches: any[] = []; if (flags.includes('g')) { let match; while ((match = regex.exec(text)) !== null) { matches.push({ match: match[0], index: match.index, groups: match.slice(1), }); if (match.index === regex.lastIndex) regex.lastIndex++; // Avoid infinite loops on zero-width matches } } else { const match = regex.exec(text); if (match) { matches.push({ match: match[0], index: match.index, groups: match.slice(1), }); } } let replacedText: string | undefined = undefined; if (replacement !== undefined) { replacedText = text.replace(new RegExp(pattern, flags), replacement); } resultData = { pattern, flags, totalMatches: matches.length, matches, replacedText, }; break; } // 7. DATA CONVERTER case 'data_converter': { const { data, fromFormat, toFormat } = args; let parsedObj: any = null; // Parse if (fromFormat === 'json') { parsedObj = typeof data === 'object' ? data : JSON.parse(data); } else if (fromFormat === 'query_string') { const params = new URLSearchParams(data); parsedObj = Object.fromEntries(params.entries()); } else if (fromFormat === 'csv') { const lines = data.trim().split('\n'); const headers = lines[0].split(',').map((h: string) => h.trim().replace(/^"|"$/g, '')); parsedObj = lines.slice(1).map((line: string) => { const vals = line.split(',').map((v: string) => v.trim().replace(/^"|"$/g, '')); const row: any = {}; headers.forEach((h: string, idx: number) => { row[h] = vals[idx] !== undefined ? vals[idx] : ''; }); return row; }); } else if (fromFormat === 'yaml') { // Simplified YAML key: value parser const lines = data.split('\n'); const obj: any = {}; lines.forEach((l: string) => { const idx = l.indexOf(':'); if (idx > 0) { const k = l.substring(0, idx).trim(); const v = l.substring(idx + 1).trim(); obj[k] = v; } }); parsedObj = obj; } // Convert if (toFormat === 'json') { resultData = JSON.stringify(parsedObj, null, 2); } else if (toFormat === 'yaml') { if (typeof parsedObj === 'object' && parsedObj !== null) { resultData = Object.entries(parsedObj) .map(([k, v]) => `${k}: ${typeof v === 'object' ? JSON.stringify(v) : v}`) .join('\n'); } else { resultData = String(parsedObj); } } else if (toFormat === 'query_string') { const params = new URLSearchParams(); if (typeof parsedObj === 'object') { Object.entries(parsedObj).forEach(([k, v]) => params.append(k, String(v))); } resultData = params.toString(); } else if (toFormat === 'csv') { if (Array.isArray(parsedObj) && parsedObj.length > 0) { const keys = Object.keys(parsedObj[0]); const headerRow = keys.join(','); const dataRows = parsedObj.map((r: any) => keys.map(k => `"${r[k] ?? ''}"`).join(',')).join('\n'); resultData = `${headerRow}\n${dataRows}`; } else if (typeof parsedObj === 'object') { resultData = `Key,Value\n` + Object.entries(parsedObj).map(([k, v]) => `"${k}","${v}"`).join('\n'); } } else if (toFormat === 'xml') { const toXml = (obj: any): string => { let xml = '\n'; Object.entries(obj).forEach(([k, v]) => { xml += ` <${k}>${v}\n`; }); xml += ''; return xml; }; resultData = toXml(parsedObj); } contentType = 'text'; break; } // 8. ENCODER DECODER case 'encoder_decoder': { const { input, action } = args; switch (action) { case 'base64_encode': resultData = Buffer.from(input).toString('base64'); break; case 'base64_decode': resultData = Buffer.from(input, 'base64').toString('utf-8'); break; case 'url_encode': resultData = encodeURIComponent(input); break; case 'url_decode': resultData = decodeURIComponent(input); break; case 'hex_encode': resultData = Buffer.from(input).toString('hex'); break; case 'hex_decode': resultData = Buffer.from(input, 'hex').toString('utf-8'); break; case 'jwt_decode': { const parts = input.split('.'); if (parts.length !== 3) throw new Error('Invalid JWT token format (expected header.payload.signature)'); const header = JSON.parse(Buffer.from(parts[0], 'base64url').toString('utf-8')); const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf-8')); resultData = { header, payload, signature: parts[2] }; break; } } break; } // 9. CRYPTO HASH GENERATOR case 'crypto_hash_generator': { const { input = '', algorithm, secretKey } = args; if (algorithm === 'uuid_v4') { resultData = crypto.randomUUID(); } else if (algorithm === 'random_hex') { resultData = crypto.randomBytes(16).toString('hex'); } else if (secretKey) { const hmac = crypto.createHmac(algorithm, secretKey); hmac.update(input); resultData = hmac.digest('hex'); } else { const hash = crypto.createHash(algorithm); hash.update(input); resultData = hash.digest('hex'); } break; } // 10. TEXT DIFF CHECKER case 'text_diff_checker': { const { originalText, modifiedText } = args; const origLines = originalText.split('\n'); const modLines = modifiedText.split('\n'); const diffs: { line: number; type: 'added' | 'removed' | 'unchanged'; content: string }[] = []; const maxLen = Math.max(origLines.length, modLines.length); let addedCount = 0; let removedCount = 0; for (let i = 0; i < maxLen; i++) { const orig = origLines[i]; const mod = modLines[i]; if (orig === mod) { diffs.push({ line: i + 1, type: 'unchanged', content: orig || '' }); } else { if (orig !== undefined) { diffs.push({ line: i + 1, type: 'removed', content: orig }); removedCount++; } if (mod !== undefined) { diffs.push({ line: i + 1, type: 'added', content: mod }); addedCount++; } } } resultData = { addedCount, removedCount, totalLines: diffs.length, diffs, }; break; } // 11. CHART GENERATOR case 'chart_generator': { const { title = 'Chart', chartType = 'bar', labels = [], values = [], primaryColor = '#3b82f6' } = args; const width = 600; const height = 350; const padding = 50; const maxVal = Math.max(...values, 1); const chartWidth = width - padding * 2; const chartHeight = height - padding * 2 - 30; let chartElements = ''; if (chartType === 'bar') { const barWidth = Math.max(10, (chartWidth / values.length) - 15); values.forEach((v: number, i: number) => { const barH = (v / maxVal) * chartHeight; const x = padding + i * (chartWidth / values.length) + 10; const y = height - padding - barH; chartElements += ` ${v} ${labels[i] || ''} `; }); } else if (chartType === 'line') { const points = values.map((v: number, i: number) => { const x = padding + (i / (values.length - 1 || 1)) * chartWidth; const y = height - padding - (v / maxVal) * chartHeight; return { x, y, v, label: labels[i] }; }); const polyPoints = points.map(p => `${p.x},${p.y}`).join(' '); chartElements += ``; points.forEach(p => { chartElements += ` ${p.v} ${p.label || ''} `; }); } else { // Pie / Donut const cx = width / 2; const cy = height / 2 + 10; const r = 90; const innerR = chartType === 'donut' ? 45 : 0; const total = values.reduce((a: number, b: number) => a + b, 0) || 1; let startAngle = 0; const colors = ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6', '#ec4899', '#06b6d4']; values.forEach((v: number, i: number) => { const sliceAngle = (v / total) * 2 * Math.PI; const endAngle = startAngle + sliceAngle; const x1 = cx + r * Math.cos(startAngle); const y1 = cy + r * Math.sin(startAngle); const x2 = cx + r * Math.cos(endAngle); const y2 = cy + r * Math.sin(endAngle); const ix1 = cx + innerR * Math.cos(startAngle); const iy1 = cy + innerR * Math.sin(startAngle); const ix2 = cx + innerR * Math.cos(endAngle); const iy2 = cy + innerR * Math.sin(endAngle); const largeArc = sliceAngle > Math.PI ? 1 : 0; const color = colors[i % colors.length]; const pathD = innerR > 0 ? `M ${ix1} ${iy1} L ${x1} ${y1} A ${r} ${r} 0 ${largeArc} 1 ${x2} ${y2} L ${ix2} ${iy2} A ${innerR} ${innerR} 0 ${largeArc} 0 ${ix1} ${iy1} Z` : `M ${cx} ${cy} L ${x1} ${y1} A ${r} ${r} 0 ${largeArc} 1 ${x2} ${y2} Z`; chartElements += ``; // Legend item chartElements += ` ${labels[i] || ''}: ${v} `; startAngle = endAngle; }); } const svg = ` ${title} ${chartElements} `.trim(); contentType = 'svg'; resultData = svg; break; } // 12. QR & BARCODE GENERATOR case 'qr_barcode_generator': { const { text, size = 200, type = 'qr' } = args; // Clean SVG generator for QR grid pattern representation const hash = crypto.createHash('md5').update(text).digest('hex'); const gridCount = 15; const cellSize = size / gridCount; let rects = ''; // Finder patterns in corners const drawFinder = (x: number, y: number) => { rects += ``; rects += ``; rects += ``; }; drawFinder(0, 0); drawFinder(gridCount - 7, 0); drawFinder(0, gridCount - 7); // Pseudorandom data modules based on hash for (let r = 0; r < gridCount; r++) { for (let c = 0; c < gridCount; c++) { // skip finder pattern regions if ((r < 7 && c < 7) || (r < 7 && c >= gridCount - 7) || (r >= gridCount - 7 && c < 7)) continue; const charCode = hash.charCodeAt((r * gridCount + c) % hash.length); if (charCode % 2 === 0) { rects += ``; } } } const svg = ` ${rects} `.trim(); contentType = 'svg'; resultData = svg; break; } // 13. ASCII ART case 'ascii_art_generator': { const { text, style, headers = [], rows = [] } = args; if (style === 'banner') { const border = '='.repeat(text.length + 8); resultData = `${border}\n|| ${text.toUpperCase()} ||\n${border}`; } else if (style === 'boxed') { const border = '+' + '-'.repeat(text.length + 4) + '+'; resultData = `${border}\n| ${text} |\n${border}`; } else if (style === 'table' && headers.length > 0) { const colWidths = headers.map((h, i) => { const maxRowLen = rows.reduce((max, row) => Math.max(max, String(row[i] || '').length), 0); return Math.max(h.length, maxRowLen) + 2; }); const renderLine = (char: string) => '+' + colWidths.map(w => char.repeat(w)).join('+') + '+'; const headerLine = '|' + headers.map((h, i) => ` ${h.padEnd(colWidths[i] - 1)}`).join('|') + '|'; const rowLines = rows.map(r => '|' + r.map((cell: any, i: number) => ` ${String(cell || '').padEnd(colWidths[i] - 1)}`).join('|') + '|'); resultData = [renderLine('-'), headerLine, renderLine('='), ...rowLines, renderLine('-')].join('\n'); } contentType = 'text'; break; } // 14. MEMORY STORE SET case 'memory_store_set': { if (!memoryStoreRef) throw new Error('Memory store service not initialized'); const item = memoryStoreRef.set(args); resultData = item; break; } // 15. MEMORY STORE GET case 'memory_store_get': { if (!memoryStoreRef) throw new Error('Memory store service not initialized'); const { key, query, tag } = args; if (key) { resultData = memoryStoreRef.get(key); } else { resultData = memoryStoreRef.search(query, tag); } break; } // 16. MEMORY STORE LIST case 'memory_store_list': { if (!memoryStoreRef) throw new Error('Memory store service not initialized'); resultData = memoryStoreRef.list(args.tagFilter, args.limit); break; } // 17. TEXT SUMMARIZE & CLASSIFY case 'text_summarize_classify': { const { text, task = 'all' } = args; const apiKey = process.env.GEMINI_API_KEY; if (apiKey && apiKey !== 'MY_GEMINI_API_KEY') { const ai = new GoogleGenAI({ apiKey }); const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: `Perform task "${task}" on the following text: "${text}" Return a structured response with key takeaways, sentiment (positive/neutral/negative), and extracted entities.`, }); resultData = response.text; contentType = 'markdown'; } else { // Heuristic summarizer const words = text.split(/\s+/); const sentences = text.split(/[.!?]+/).filter((s: string) => s.trim().length > 0); const summary = sentences.slice(0, 3).join('. ') + '.'; resultData = { task, wordCount: words.length, sentenceCount: sentences.length, summary, sentiment: text.toLowerCase().includes('great') || text.toLowerCase().includes('excellent') ? 'POSITIVE' : 'NEUTRAL', extractedKeywords: [...new Set(words.filter((w: string) => w.length > 6))].slice(0, 8), }; } break; } // 18. NETWORK UTILITIES case 'network_utilities': { const { action, target } = args; if (action === 'parse_url') { const parsed = new URL(target); resultData = { protocol: parsed.protocol, hostname: parsed.hostname, port: parsed.port || (parsed.protocol === 'https:' ? '443' : '80'), pathname: parsed.pathname, searchParams: Object.fromEntries(parsed.searchParams.entries()), hash: parsed.hash, }; } else if (action === 'ip_subnet') { const [ip, maskStr = '24'] = target.split('/'); const maskBits = parseInt(maskStr, 10); const totalHosts = Math.pow(2, 32 - maskBits) - 2; resultData = { ipAddress: ip, subnetMaskBits: maskBits, usableHosts: totalHosts > 0 ? totalHosts : 0, ipClass: ip.startsWith('10.') || ip.startsWith('192.168.') || ip.startsWith('172.') ? 'Private (RFC 1918)' : 'Public', }; } else if (action === 'ping_simulate') { resultData = { target, status: 'ONLINE', latencyMs: Math.floor(Math.random() * 25) + 12, packetsSent: 4, packetsReceived: 4, lossPercentage: '0%', }; } else if (action === 'parse_user_agent') { resultData = { raw: target, browser: target.includes('Chrome') ? 'Chrome' : target.includes('Safari') ? 'Safari' : 'Custom/Agent', isBot: target.toLowerCase().includes('bot') || target.toLowerCase().includes('agent'), }; } break; } // 19. CRON CALCULATOR case 'cron_calculator': { const { expression, count = 5 } = args; const parts = expression.trim().split(/\s+/); if (parts.length !== 5) { throw new Error('Cron expression must consist of exactly 5 fields (minute hour day-of-month month day-of-week)'); } const [min, hour, dom, mon, dow] = parts; const explain = `Executes at minute (${min}), hour (${hour}), day of month (${dom}), month (${mon}), day of week (${dow}).`; // Calculate upcoming simulated execution times const upcoming: string[] = []; let now = new Date(); for (let i = 1; i <= count; i++) { const future = new Date(now.getTime() + i * 15 * 60 * 1000); // 15-min intervals simulation upcoming.push(future.toISOString()); } resultData = { expression, humanExplanation: explain, valid: true, upcomingExecutions: upcoming, }; break; } default: { const isLocalModelTool = LOCAL_MODEL_TOOLS.some(t => t.name === toolName); if (isLocalModelTool) { return await executeLocalModelTool(toolName, args); } throw new Error(`Tool "${toolName}" not found or not supported.`); } } const durationMs = Date.now() - startTime; return { success: true, toolName, result: resultData, executionTimeMs: durationMs, contentType, }; } catch (err: any) { return { success: false, toolName, result: null, error: err.message || 'Tool execution failed', executionTimeMs: Date.now() - startTime, }; } }