(status: number, errorMessage?: string)
| 9 | * Maps API error responses to specific, actionable user-facing messages. |
| 10 | */ |
| 11 | export function formatAPIError(status: number, errorMessage?: string): string { |
| 12 | const msg = (errorMessage || '').toLowerCase() |
| 13 | |
| 14 | // Authentication / API key issues |
| 15 | if (status === 401 || msg.includes('invalid api key') || msg.includes('no auth') || msg.includes('unauthorized')) { |
| 16 | return 'Your OpenRouter API key is invalid or expired. Go to Settings → API Key and enter a valid key from [openrouter.ai/keys](https://openrouter.ai/keys).' |
| 17 | } |
| 18 | if (status === 403) { |
| 19 | if (msg.includes('insufficient') || msg.includes('credit') || msg.includes('balance') || msg.includes('payment')) { |
| 20 | return 'Your OpenRouter account has insufficient credits. Add credits at [openrouter.ai/credits](https://openrouter.ai/credits), then try again.' |
| 21 | } |
| 22 | return 'Access denied by OpenRouter. Your API key may lack permissions for this model, or your account may need credits. Check your key at [openrouter.ai/keys](https://openrouter.ai/keys).' |
| 23 | } |
| 24 | |
| 25 | // Rate limiting |
| 26 | if (status === 429 || msg.includes('rate limit') || msg.includes('too many requests')) { |
| 27 | return 'Rate limited by OpenRouter. Wait a moment and try again, or upgrade your plan at [openrouter.ai](https://openrouter.ai) for higher limits.' |
| 28 | } |
| 29 | |
| 30 | // Model-specific issues |
| 31 | if (status === 404 || msg.includes('not found') || msg.includes('no endpoints')) { |
| 32 | return 'The selected model is currently unavailable on OpenRouter. Try a different model from the model selector.' |
| 33 | } |
| 34 | |
| 35 | // Content moderation |
| 36 | if (msg.includes('moderation') || msg.includes('content policy') || msg.includes('flagged')) { |
| 37 | return 'Your message was flagged by the model\'s content filter. Try rephrasing your prompt.' |
| 38 | } |
| 39 | |
| 40 | // Upstream / server errors |
| 41 | if (status === 502 || status === 503 || msg.includes('overloaded') || msg.includes('capacity')) { |
| 42 | return 'The model provider is temporarily overloaded. Wait a moment and try again, or switch to a different model.' |
| 43 | } |
| 44 | if (status >= 500) { |
| 45 | return 'OpenRouter is experiencing server issues. Try again in a moment.' |
| 46 | } |
| 47 | |
| 48 | // Timeout |
| 49 | if (msg.includes('timeout') || msg.includes('timed out')) { |
| 50 | return 'The request timed out. The model may be under heavy load — try again or switch to a faster model.' |
| 51 | } |
| 52 | |
| 53 | // Fallback |
| 54 | return errorMessage || `API error (${status}). Check your API key and network connection.` |
| 55 | } |
| 56 | |
| 57 | interface Message { |
| 58 | role: 'system' | 'user' | 'assistant' |
no outgoing calls
no test coverage detected