Spaces:
Sleeping
Sleeping
| export function formatTimestamp(timestamp: string): string { | |
| const date = new Date(timestamp); | |
| return date.toLocaleTimeString('en-US', { | |
| hour: '2-digit', | |
| minute: '2-digit', | |
| second: '2-digit', | |
| }); | |
| } | |
| export function formatDate(timestamp: string): string { | |
| const date = new Date(timestamp); | |
| return date.toLocaleDateString('en-US', { | |
| month: 'short', | |
| day: 'numeric', | |
| year: 'numeric', | |
| }); | |
| } | |
| export function formatDuration(ms: number): string { | |
| const seconds = Math.floor(ms / 1000); | |
| const minutes = Math.floor(seconds / 60); | |
| const hours = Math.floor(minutes / 60); | |
| if (hours > 0) { | |
| return `${hours}h ${minutes % 60}m`; | |
| } | |
| if (minutes > 0) { | |
| return `${minutes}m ${seconds % 60}s`; | |
| } | |
| return `${seconds}s`; | |
| } | |
| export function formatNumber(num: number, decimals = 2): string { | |
| if (Math.abs(num) >= 1e6) { | |
| return `${(num / 1e6).toFixed(decimals)}M`; | |
| } | |
| if (Math.abs(num) >= 1e3) { | |
| return `${(num / 1e3).toFixed(decimals)}K`; | |
| } | |
| return num.toFixed(decimals); | |
| } | |
| export function formatReward(reward: number): string { | |
| const sign = reward >= 0 ? '+' : ''; | |
| return `${sign}${reward.toFixed(3)}`; | |
| } | |
| export function truncateText(text: string, maxLength: number): string { | |
| if (text.length <= maxLength) return text; | |
| return `${text.slice(0, maxLength - 3)}...`; | |
| } | |
| export function classNames(...classes: (string | boolean | undefined | null)[]): string { | |
| return classes.filter(Boolean).join(' '); | |
| } | |
| export function getStatusColor(status: string): string { | |
| const colors: Record<string, string> = { | |
| idle: 'yellow', | |
| thinking: 'blue', | |
| acting: 'green', | |
| waiting: 'orange', | |
| error: 'red', | |
| running: 'green', | |
| completed: 'green', | |
| failed: 'red', | |
| pending: 'gray', | |
| timeout: 'orange', | |
| }; | |
| return colors[status] ?? 'gray'; | |
| } | |
| export function getRoleIcon(role: string): string { | |
| const icons: Record<string, string> = { | |
| navigator: 'π§', | |
| extractor: 'π', | |
| validator: 'β ', | |
| coordinator: 'π―', | |
| }; | |
| return icons[role] ?? 'π€'; | |
| } | |
| export function getActionIcon(actionType: string): string { | |
| const icons: Record<string, string> = { | |
| navigate: 'π', | |
| click: 'π', | |
| extract: 'π€', | |
| scroll: 'π', | |
| input: 'β¨οΈ', | |
| wait: 'β³', | |
| screenshot: 'πΈ', | |
| execute_tool: 'π§', | |
| delegate: 'π₯', | |
| terminate: 'π', | |
| }; | |
| return icons[actionType] ?? 'β‘'; | |
| } | |
| export function debounce<T extends (...args: unknown[]) => unknown>( | |
| func: T, | |
| wait: number | |
| ): (...args: Parameters<T>) => void { | |
| let timeout: ReturnType<typeof setTimeout> | null = null; | |
| return (...args: Parameters<T>) => { | |
| if (timeout) clearTimeout(timeout); | |
| timeout = setTimeout(() => func(...args), wait); | |
| }; | |
| } | |
| export function throttle<T extends (...args: unknown[]) => unknown>( | |
| func: T, | |
| limit: number | |
| ): (...args: Parameters<T>) => void { | |
| let inThrottle = false; | |
| return (...args: Parameters<T>) => { | |
| if (!inThrottle) { | |
| func(...args); | |
| inThrottle = true; | |
| setTimeout(() => (inThrottle = false), limit); | |
| } | |
| }; | |
| } | |
| export function generateId(): string { | |
| return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 9)}`; | |
| } | |
| export function parseJSON<T>(json: string, fallback: T): T { | |
| try { | |
| return JSON.parse(json) as T; | |
| } catch { | |
| return fallback; | |
| } | |
| } | |
| export function calculateProgress(current: number, total: number): number { | |
| if (total === 0) return 0; | |
| return Math.min(Math.round((current / total) * 100), 100); | |
| } | |
| export function groupBy<T>(array: T[], key: keyof T): Record<string, T[]> { | |
| return array.reduce((groups, item) => { | |
| const groupKey = String(item[key]); | |
| return { | |
| ...groups, | |
| [groupKey]: [...(groups[groupKey] || []), item], | |
| }; | |
| }, {} as Record<string, T[]>); | |
| } | |
| export function sortByTimestamp<T extends { timestamp: string }>( | |
| items: T[], | |
| order: 'asc' | 'desc' = 'desc' | |
| ): T[] { | |
| return [...items].sort((a, b) => { | |
| const timeA = new Date(a.timestamp).getTime(); | |
| const timeB = new Date(b.timestamp).getTime(); | |
| return order === 'asc' ? timeA - timeB : timeB - timeA; | |
| }); | |
| } | |