(error: unknown)
| 151 | } |
| 152 | |
| 153 | function normalizeProviderError(error: unknown): ProviderErrorFacts | undefined { |
| 154 | const target = providerErrorTarget(error); |
| 155 | if (target instanceof Error) { |
| 156 | const responseHeaders = responseHeadersFromError(target); |
| 157 | const code = 'code' in target ? String((target as { code?: unknown }).code) : ''; |
| 158 | const statusCode = |
| 159 | 'statusCode' in target |
| 160 | ? String((target as { statusCode?: unknown }).statusCode) |
| 161 | : 'status' in target |
| 162 | ? String((target as { status?: unknown }).status) |
| 163 | : ''; |
| 164 | const rawBody = (target as { responseBody?: unknown }).responseBody; |
| 165 | const body = typeof rawBody === 'string' ? rawBody : ''; |
| 166 | const structuredCodes: string[] = []; |
| 167 | collectStructuredCodes((target as { data?: unknown }).data, structuredCodes); |
| 168 | if (structuredCodes.length === 0 && body) { |
| 169 | // The failed-response handler keeps the raw body even when the provider |
| 170 | // JSON failed the schema (which is exactly when `data` is absent). |
| 171 | try { |
| 172 | collectStructuredCodes(JSON.parse(body), structuredCodes); |
| 173 | } catch { |
| 174 | // Not JSON — no structured evidence. |
| 175 | } |
| 176 | } |
| 177 | return { |
| 178 | target, |
| 179 | // The raw body joins the text evidence: when the provider JSON fails |
| 180 | // the error schema, `message` degrades to the statusText and the body |
| 181 | // is the ONLY carrier of the provider's wording (e.g. an |
| 182 | // OpenAI-compatible `{error: string}` overflow). Positives and vetoes |
| 183 | // both run over the same full text. |
| 184 | evidence: { |
| 185 | text: `${target.name} ${code} ${statusCode} ${target.message}${body ? ` ${body}` : ''}`.toLowerCase(), |
| 186 | statusCode, |
| 187 | code, |
| 188 | structuredCodes, |
| 189 | }, |
| 190 | summarySources: providerFailureSources(target), |
| 191 | ...(responseHeaders ? { responseHeaders } : {}), |
| 192 | }; |
| 193 | } |
| 194 | if (typeof target === 'string') { |
| 195 | const parsed = parsedProviderValue(target); |
| 196 | const structuredCodes: string[] = []; |
| 197 | if (parsed !== undefined) collectStructuredCodes(parsed, structuredCodes); |
| 198 | return { |
| 199 | target, |
| 200 | evidence: { text: target.toLowerCase(), statusCode: '', code: '', structuredCodes }, |
| 201 | summarySources: providerFailureSources(parsed), |
| 202 | ...(parsed === undefined |
| 203 | ? { bareMessage: target } |
| 204 | : typeof parsed === 'string' |
| 205 | ? { bareMessage: parsed } |
| 206 | : {}), |
| 207 | }; |
| 208 | } |
| 209 | if (typeof target === 'object' && target !== null) { |
| 210 | const record = target as Record<string, unknown>; |
no test coverage detected