(raw: string)
| 9 | * explanation and a concrete next step. |
| 10 | */ |
| 11 | export function explainStreamError(raw: string): string { |
| 12 | const msg = String(raw ?? '').trim(); |
| 13 | const is429 = /\b429\b|too many requests|rate.?limit/i.test(msg); |
| 14 | const is401 = /\b401\b|unauthorized|invalid api key|no api key/i.test(msg); |
| 15 | const is402 = /\b402\b|payment required|insufficient (credit|quota|balance)|quota/i.test(msg); |
| 16 | const is5xx = /\b50[0-9]\b|server error|bad gateway|service unavailable/i.test(msg); |
| 17 | |
| 18 | if (is429) { |
| 19 | return ( |
| 20 | `Rate limited (429): the model provider is refusing new requests right now.\n` + |
| 21 | `This is the provider throttling you, not a QodeX error. QodeX already retried with backoff.\n` + |
| 22 | `What to do:\n` + |
| 23 | ` • If you're on a free/shared model (e.g. an OpenRouter ":free" model or a free Gemini tier),\n` + |
| 24 | ` that pool is heavily contended — wait a bit, or switch to a paid model for reliable throughput.\n` + |
| 25 | ` • Try another model with --model (e.g. openai/gpt-4o-mini), or run a local model with no limits.\n` + |
| 26 | ` • If you have a Retry-After hint from the provider dashboard, wait that long.\n` + |
| 27 | `(raw: ${msg.slice(0, 160)})` |
| 28 | ); |
| 29 | } |
| 30 | if (is401) { |
| 31 | return ( |
| 32 | `Authentication failed (401): the provider rejected your API key.\n` + |
| 33 | `Check that the right env var is exported and matches the provider in your config.\n` + |
| 34 | `(raw: ${msg.slice(0, 160)})` |
| 35 | ); |
| 36 | } |
| 37 | if (is402) { |
| 38 | return ( |
| 39 | `Payment/quota issue (402): the provider says this key is out of credit or quota.\n` + |
| 40 | `Top up the account or switch to a free/local model with --model.\n` + |
| 41 | `(raw: ${msg.slice(0, 160)})` |
| 42 | ); |
| 43 | } |
| 44 | if (is5xx) { |
| 45 | return ( |
| 46 | `Provider server error: the model endpoint failed on its side (5xx). QodeX retried.\n` + |
| 47 | `Wait a moment and retry, or switch model with --model.\n` + |
| 48 | `(raw: ${msg.slice(0, 160)})` |
| 49 | ); |
| 50 | } |
| 51 | return msg; |
| 52 | } |
| 53 | |
| 54 | export function transformError(err: any, toolCall?: ToolCall): string { |
| 55 | const code = err.code ?? ''; |
no outgoing calls
no test coverage detected