UNPKG

call-ai

Version:

Lightweight library for making AI API calls with streaming support

144 lines 6.68 kB
import { keyStore, globalDebug, isNewKeyError, refreshApiKey } from "./key-management.js"; import { CallAIError } from "./types.js"; async function handleApiError(ierror, context, debug = globalDebug, options = {}) { const error = ierror; const errorMessage = error?.message || String(error); const status = error?.status || error?.statusCode || error?.response?.status || (errorMessage.match(/status: (\d+)/i)?.[1] && parseInt(errorMessage.match(/status: (\d+)/i)?.[1] ?? "500")); const isMissingKeyError = errorMessage.includes("API key is required"); if (debug) { console.error(`[callAi:error] ${context} error:`, { message: errorMessage, status, name: error?.name, cause: error?.cause, isMissingKey: isMissingKeyError, }); } if (options.skipRefresh) { throw error; } const needsNewKey = isNewKeyError(error, debug) || isMissingKeyError; if (needsNewKey) { if (debug) { console.log(`[callAi:key-refresh] Error suggests API key issue, attempting refresh...`); } try { const currentKey = options.apiKey || keyStore().current; const endpoint = options.endpoint || keyStore().refreshEndpoint; const refreshToken = options.refreshToken || keyStore().refreshToken; try { const { apiKey, topup } = await refreshApiKey(options, currentKey, endpoint, refreshToken, debug); if (keyStore().current !== apiKey) { keyStore().current = apiKey; } if (debug) { console.log(`[callAi:key-refresh] ${topup ? "Topped up" : "Refreshed"} API key successfully`); } return; } catch (initialRefreshError) { if (options.updateRefreshToken && refreshToken) { if (debug) { console.log(`[callAi:key-refresh] Initial refresh failed, attempting to update refresh token`); } try { const newRefreshToken = await options.updateRefreshToken(refreshToken); if (newRefreshToken && newRefreshToken !== refreshToken) { if (debug) { console.log(`[callAi:key-refresh] Got new refresh token, retrying key refresh`); } keyStore().refreshToken = newRefreshToken; const { apiKey, topup } = await refreshApiKey(options, currentKey, endpoint, newRefreshToken, debug); if (keyStore().current !== apiKey) { keyStore().current = apiKey; } if (debug) { console.log(`[callAi:key-refresh] ${topup ? "Topped up" : "Refreshed"} API key successfully with new refresh token`); } return; } else { if (debug) { console.log(`[callAi:key-refresh] No new refresh token provided or same token returned, cannot retry`); } throw initialRefreshError; } } catch (tokenUpdateError) { if (debug) { console.error(`[callAi:key-refresh] Failed to update refresh token:`, tokenUpdateError); } throw initialRefreshError; } } else { throw initialRefreshError; } } } catch (refreshError) { if (debug) { console.error(`[callAi:key-refresh] API key refresh failed:`, refreshError); } const detailedError = new CallAIError({ message: `${errorMessage} (Key refresh failed: ${refreshError instanceof Error ? refreshError.message : String(refreshError)})`, originalError: error, refreshError, status: status || 401, contentType: "text/plain", }); throw detailedError; } } const detailedError = new CallAIError({ message: `${context}: ${errorMessage}`, originalError: error, status: status || 500, errorType: error.name || "Error", }); throw detailedError; } async function checkForInvalidModelError(response, model, debug = globalDebug) { if (response.status < 400 || response.status >= 500) { return { isInvalidModel: false }; } const responseClone = response.clone(); let errorData; try { errorData = await responseClone.json(); } catch (e) { try { const text = await responseClone.text(); errorData = { error: text }; } catch (e) { errorData = { error: `Error ${response.status}: ${response.statusText}` }; } } const isInvalidModelError = response.status === 404 || response.status === 400 || (errorData && ((typeof errorData.error === "string" && (errorData.error.toLowerCase().includes("model") || errorData.error.toLowerCase().includes("engine") || errorData.error.toLowerCase().includes("not found") || errorData.error.toLowerCase().includes("invalid") || errorData.error.toLowerCase().includes("unavailable"))) || (errorData.error?.message && typeof errorData.error.message === "string" && (errorData.error.message.toLowerCase().includes("model") || errorData.error.message.toLowerCase().includes("engine") || errorData.error.message.toLowerCase().includes("not found") || errorData.error.message.toLowerCase().includes("invalid") || errorData.error.message.toLowerCase().includes("unavailable"))))); if (debug && isInvalidModelError) { console.log(`[callAi:model-fallback] Detected invalid model error for "${model}":`, errorData); } return { isInvalidModel: isInvalidModelError, errorData }; } export { handleApiError, checkForInvalidModelError }; //# sourceMappingURL=error-handling.js.map