|
| 1 | +import { buildTool, type AgentTool } from '../core/AgentTool' |
| 2 | +import type { ToolContext } from '../core/ToolContext' |
| 3 | +import type { ToolResult } from '../core/ToolResult' |
| 4 | +import { ToolCapabilities } from '../core/ToolCapabilities' |
| 5 | + |
| 6 | +function formatBytes(bytes: number): string { |
| 7 | + if (bytes < 1024) return `${bytes} B` |
| 8 | + if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB` |
| 9 | + if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB` |
| 10 | + return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB` |
| 11 | +} |
| 12 | + |
| 13 | +export const MemoryInfoTool: AgentTool = buildTool({ |
| 14 | + name: 'memory_info', |
| 15 | + aliases: ['meminfo', 'system_info'], |
| 16 | + description: 'Display current memory usage, CPU information, and system resource utilization. Provides heap usage, total memory, CPU core count, and device memory. Useful for diagnosing performance issues or checking resource availability.', |
| 17 | + inputSchema: { |
| 18 | + type: 'object', |
| 19 | + properties: { |
| 20 | + detailed: { |
| 21 | + type: 'boolean', |
| 22 | + description: 'If true, returns detailed memory breakdown including heap stats', |
| 23 | + }, |
| 24 | + }, |
| 25 | + required: [], |
| 26 | + }, |
| 27 | + promptCategory: 'utilities', |
| 28 | + promptPriority: 55, |
| 29 | + isReadOnly: () => true, |
| 30 | + isConcurrencySafe: () => true, |
| 31 | + requiredCapabilities: () => [ToolCapabilities.READ_ONLY], |
| 32 | + getActivityDescription: () => 'Checking system memory', |
| 33 | + execute: async (_ctx: ToolContext, input: Record<string, unknown>): Promise<ToolResult> => { |
| 34 | + const detailed = input.detailed === true |
| 35 | + let heapUsed = 0 |
| 36 | + let heapTotal = 0 |
| 37 | + let rss = 0 |
| 38 | + |
| 39 | + try { |
| 40 | + const mem = process.memoryUsage() |
| 41 | + heapUsed = mem.heapUsed |
| 42 | + heapTotal = mem.heapTotal |
| 43 | + rss = mem.rss |
| 44 | + } catch { |
| 45 | + // process.memoryUsage may not be available in all environments |
| 46 | + } |
| 47 | + |
| 48 | + const cpuCores = navigator.hardwareConcurrency || 0 |
| 49 | + const deviceMem = (navigator as unknown as { deviceMemory?: number }).deviceMemory || 0 |
| 50 | + |
| 51 | + const summary: Record<string, string> = { |
| 52 | + 'Heap Used': formatBytes(heapUsed), |
| 53 | + 'Heap Total': formatBytes(heapTotal), |
| 54 | + 'RSS': formatBytes(rss), |
| 55 | + 'Heap Usage': heapTotal > 0 ? `${((heapUsed / heapTotal) * 100).toFixed(1)}%` : 'N/A', |
| 56 | + 'CPU Cores': String(cpuCores), |
| 57 | + 'Device Memory': deviceMem > 0 ? `${deviceMem} GB` : 'N/A', |
| 58 | + } |
| 59 | + |
| 60 | + let text = '## System Memory Info\n\n' |
| 61 | + text += '| Metric | Value |\n|---|---|\n' |
| 62 | + for (const [key, val] of Object.entries(summary)) { |
| 63 | + text += `| ${key} | ${val} |\n` |
| 64 | + } |
| 65 | + |
| 66 | + if (detailed) { |
| 67 | + const heapDiff = heapTotal - heapUsed |
| 68 | + text += `\n### Details\n` |
| 69 | + text += `- Heap fragmentation: ${formatBytes(heapDiff)} free (${heapTotal > 0 ? ((heapDiff / heapTotal) * 100).toFixed(1) : 'N/A'}% of total)\n` |
| 70 | + text += `- Available device memory: ${deviceMem > 0 ? `${deviceMem} GB` : 'unknown'}\n` |
| 71 | + text += `- Logical CPU cores: ${cpuCores}\n` |
| 72 | + } |
| 73 | + |
| 74 | + return { |
| 75 | + data: { |
| 76 | + heapUsed, |
| 77 | + heapTotal, |
| 78 | + rss, |
| 79 | + cpuCores, |
| 80 | + deviceMemoryGB: deviceMem, |
| 81 | + }, |
| 82 | + meta: { type: 'memory_info' }, |
| 83 | + newMessages: [{ role: 'user', content: text }], |
| 84 | + } |
| 85 | + }, |
| 86 | +}) |
0 commit comments