/** * report.js — human-readable summary generator + severity logic */ /** * Compute severity for a parsed provider result. * @param {Object} provider * @returns {'critical'|'warning'|'ok'|'unknown'} */ export function getSeverity(provider) { if (provider.type === 'teams-direct') { if (provider.status === 'rejected') return 'critical'; if (provider.status === 'policy_rejected') return 'critical'; if (provider.utilization_7d > 0.85) return 'warning'; if (provider.utilization_5h > 0.7) return 'warning'; return 'ok'; } if (provider.type === 'shelley-proxy') { const tokenPct = 1 - (provider.tokens_remaining / provider.tokens_limit); if (tokenPct > 0.85) return 'warning'; return 'ok'; } if (provider.type === 'gemini-api') { if (provider.status === 'exhausted') return 'critical'; if (provider.status === 'ok') return 'ok'; return 'unknown'; } if (provider.type === 'xai-api') { if (provider.status === 'rate_limited') return 'critical'; if (provider.status === 'ok') { const reqPct = provider.requests_remaining / provider.requests_limit; const tokPct = provider.tokens_remaining / provider.tokens_limit; if ((reqPct < 0.1) || (tokPct < 0.1)) return 'warning'; return 'ok'; } return 'unknown'; } return 'unknown'; } /** * Format seconds as "Xh Ym" or "Xm" or "Xs". */ function formatDuration(seconds) { if (seconds == null || isNaN(seconds) || seconds < 0) return '?'; const h = Math.floor(seconds / 3600); const m = Math.floor((seconds % 3600) / 60); const s = seconds % 60; if (h > 0) return `${h}h ${m}m`; if (m > 0) return `${m}m`; return `${s}s`; } /** * Format a float as a percentage string. */ function pct(v) { if (v == null) return '?'; return `${Math.round(v * 100)}%`; } /** * Severity badge string. */ function badge(severity) { switch (severity) { case 'critical': return '[CRITICAL]'; case 'warning': return '[WARNING] '; case 'ok': return '[OK] '; default: return '[UNKNOWN] '; } } /** * Generate a human-readable summary from a full monitor result. * @param {Object} result — { timestamp, providers: { name: {...} } } * @returns {string} */ export function generateReport(result) { const ts = result.timestamp ? result.timestamp.replace('T', ' ').replace(/\.\d+Z$/, ' UTC').replace('Z', ' UTC') : new Date().toUTCString(); const lines = []; const width = 60; lines.push(`Token Monitor — ${ts}`); lines.push('═'.repeat(width)); lines.push(''); const counts = { critical: 0, warning: 0, ok: 0, unknown: 0 }; for (const [name, p] of Object.entries(result.providers)) { const sev = p.severity || getSeverity(p); counts[sev] = (counts[sev] || 0) + 1; const b = badge(sev); let detail = ''; if (p.type === 'teams-direct') { if (p.status === 'invalid_key') { detail = 'Invalid API key (401)'; } else if (p.status === 'policy_rejected') { detail = `POLICY BLOCKED — 7d: ${pct(p.utilization_7d)} | extra-usage billing required`; } else if (p.status === 'rejected') { const resetIn = formatDuration(p.reset_in_seconds); detail = `MAXED — 7d: ${pct(p.utilization_7d)} | resets in ${resetIn}`; } else { detail = `5h: ${pct(p.utilization_5h)} | 7d: ${pct(p.utilization_7d)}`; if (p.reset_in_seconds != null) { detail += ` | resets in ${formatDuration(p.reset_in_seconds)}`; } } } else if (p.type === 'shelley-proxy') { if (p.status === 'error') { detail = `Error: ${p.message || 'unknown'}`; } else { detail = `tokens: ${p.tokens_remaining?.toLocaleString()}/${p.tokens_limit?.toLocaleString()}`; if (p.cost_per_call_usd != null) { detail += ` | cost: $${p.cost_per_call_usd}/call`; } } } else if (p.type === 'api-direct') { detail = p.message || 'No billing data available'; } else if (p.type === 'gemini-api') { if (p.status === 'invalid_key') { detail = 'Invalid API key (401)'; } else if (p.status === 'no_key') { detail = 'No API key configured'; } else if (p.status === 'exhausted') { const retryIn = p.retry_delay_seconds ? formatDuration(p.retry_delay_seconds) : '?'; const violated = p.quota_violations?.length || 0; detail = `EXHAUSTED — retry in ${retryIn} | ${violated} quota(s) violated`; } else if (p.status === 'ok') { detail = 'Reachable — no quota depth visible'; } else if (p.status === 'error') { detail = `Error: ${p.message || 'unknown'}`; } } else if (p.type === 'xai-api') { if (p.status === 'no_key') { detail = 'No API key configured'; } else if (p.status === 'invalid_key') { detail = 'Invalid API key (401)'; } else if (p.status === 'rate_limited') { detail = 'Rate limited (429)'; } else if (p.status === 'ok') { const reqPct = p.requests_limit ? `${p.requests_remaining}/${p.requests_limit} req` : ''; const tokPct = p.tokens_limit ? ` | ${p.tokens_remaining?.toLocaleString()}/${p.tokens_limit?.toLocaleString()} tok` : ''; detail = reqPct + tokPct || 'OK'; } else if (p.status === 'error') { detail = `Error: ${p.message || 'unknown'}`; } } else { detail = p.message || ''; } // Pad provider name to 14 chars const paddedName = name.padEnd(14); lines.push(`${paddedName} ${b} ${detail}`); } lines.push(''); lines.push('─'.repeat(width)); const parts = []; if (counts.critical) parts.push(`${counts.critical} CRITICAL`); if (counts.warning) parts.push(`${counts.warning} WARNING`); if (counts.ok) parts.push(`${counts.ok} OK`); if (counts.unknown) parts.push(`${counts.unknown} UNKNOWN`); lines.push(`Overall: ${parts.join(', ') || 'no providers'}`); lines.push(''); return lines.join('\n'); }