call-ai 0.7.0-dev-preview-10 → 0.7.0-dev-preview-13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/api.js +109 -53
  2. package/package.json +1 -1
package/dist/api.js CHANGED
@@ -63,64 +63,120 @@ function callAI(prompt, options = {}) {
63
63
  // Explicitly check for HTTP error status and log extensively
64
64
  console.log(`[callAI:${PACKAGE_VERSION}] Response.ok =`, response.ok);
65
65
  console.log(`[callAI:${PACKAGE_VERSION}] Response.status =`, response.status);
66
+ console.log(`[callAI:${PACKAGE_VERSION}] Response.statusText =`, response.statusText);
66
67
  console.log(`[callAI:${PACKAGE_VERSION}] Response.type =`, response.type);
67
- // Enhanced error handling with more debugging - MUST check !response.ok
68
- if (!response.ok) {
69
- console.log(`[callAI:${PACKAGE_VERSION}] Detected error response with status:`, response.status);
70
- if (options.debug) {
71
- console.error(`[callAI:${PACKAGE_VERSION}] HTTP Error:`, response.status, response.statusText, response.url);
72
- }
73
- // Check if this is an invalid model error
74
- console.log(`[callAI:${PACKAGE_VERSION}] Checking for invalid model error...`);
75
- let isInvalidModel = false;
76
- let errorData = null;
77
- try {
78
- const result = await checkForInvalidModelError(response.clone(), // Clone response since we'll need to read body twice
79
- model, false, options.skipRetry);
80
- isInvalidModel = result.isInvalidModel;
81
- errorData = result.errorData;
82
- console.log(`[callAI:${PACKAGE_VERSION}] Invalid model check result:`, isInvalidModel);
83
- }
84
- catch (checkError) {
85
- console.error(`[callAI:${PACKAGE_VERSION}] Error during invalid model check:`, checkError);
86
- }
87
- if (isInvalidModel && !options.skipRetry) {
88
- if (options.debug) {
89
- console.log(`[callAI:${PACKAGE_VERSION}] Retrying with fallback model: ${FALLBACK_MODEL}`);
68
+ // Double check for content-type to see if there's a mismatch in error response handling
69
+ const contentType = response.headers.get('content-type') || '';
70
+ console.log(`[callAI:${PACKAGE_VERSION}] Content-Type =`, contentType);
71
+ // Browser-compatible error handling - must check BOTH status code AND content-type
72
+ // Some browsers will report status 200 for SSE streams even when server returns 400
73
+ const hasHttpError = !response.ok || response.status >= 400;
74
+ const hasJsonError = contentType.includes('application/json');
75
+ if (hasHttpError || hasJsonError) {
76
+ console.log(`[callAI:${PACKAGE_VERSION}] ⚠️ Error detected - HTTP Status: ${response.status}, Content-Type: ${contentType}`);
77
+ // Handle the error with fallback model if appropriate
78
+ if (!options.skipRetry) {
79
+ const clonedResponse = response.clone();
80
+ let isInvalidModel = false;
81
+ try {
82
+ // Check if this is an invalid model error
83
+ const modelCheckResult = await checkForInvalidModelError(clonedResponse, model, false, options.skipRetry);
84
+ isInvalidModel = modelCheckResult.isInvalidModel;
85
+ if (isInvalidModel) {
86
+ if (options.debug) {
87
+ console.log(`[callAI:${PACKAGE_VERSION}] Retrying with fallback model: ${FALLBACK_MODEL}`);
88
+ }
89
+ // Retry with fallback model
90
+ return await callAI(prompt, { ...options, model: FALLBACK_MODEL });
91
+ }
92
+ }
93
+ catch (modelCheckError) {
94
+ console.error(`[callAI:${PACKAGE_VERSION}] Error during model check:`, modelCheckError);
95
+ // Continue with normal error handling
90
96
  }
91
- // Retry with fallback model - it will return a promise
92
- const result = await callAI(prompt, { ...options, model: FALLBACK_MODEL });
93
- return result;
94
97
  }
95
- // Get full error text from body
96
- console.log(`[callAI:${PACKAGE_VERSION}] Reading error response body...`);
97
- let errorText = "";
98
+ // Extract error details from response
98
99
  try {
99
- errorText = await response.text();
100
- console.log(`[callAI:${PACKAGE_VERSION}] Error response body:`, errorText);
100
+ // Try to get error details from the response body
101
+ const errorBody = await response.text();
102
+ console.log(`[callAI:${PACKAGE_VERSION}] Error body:`, errorBody);
103
+ try {
104
+ // Try to parse JSON error
105
+ const errorJson = JSON.parse(errorBody);
106
+ console.log(`[callAI:${PACKAGE_VERSION}] Parsed error:`, errorJson);
107
+ // Extract message from OpenRouter error format
108
+ let errorMessage = '';
109
+ // Handle common error formats
110
+ if (errorJson.error && typeof errorJson.error === 'object' && errorJson.error.message) {
111
+ // OpenRouter/OpenAI format: { error: { message: "..." } }
112
+ errorMessage = errorJson.error.message;
113
+ }
114
+ else if (errorJson.error && typeof errorJson.error === 'string') {
115
+ // Simple error format: { error: "..." }
116
+ errorMessage = errorJson.error;
117
+ }
118
+ else if (errorJson.message) {
119
+ // Generic format: { message: "..." }
120
+ errorMessage = errorJson.message;
121
+ }
122
+ else {
123
+ // Fallback with status details
124
+ errorMessage = `API returned ${response.status}: ${response.statusText}`;
125
+ }
126
+ // Add status details to error message if not already included
127
+ if (!errorMessage.includes(response.status.toString())) {
128
+ errorMessage = `${errorMessage} (Status: ${response.status})`;
129
+ }
130
+ console.log(`[callAI:${PACKAGE_VERSION}] Extracted error message:`, errorMessage);
131
+ // Create error with standard format
132
+ const error = new Error(errorMessage);
133
+ // Add useful metadata
134
+ error.status = response.status;
135
+ error.statusText = response.statusText;
136
+ error.details = errorJson;
137
+ error.contentType = contentType;
138
+ throw error;
139
+ }
140
+ catch (jsonError) {
141
+ // If JSON parsing fails, extract a useful message from the raw error body
142
+ console.log(`[callAI:${PACKAGE_VERSION}] JSON parse error:`, jsonError);
143
+ // Try to extract a useful message even from non-JSON text
144
+ let errorMessage = '';
145
+ // Check if it's a plain text error message
146
+ if (errorBody && errorBody.trim().length > 0) {
147
+ // Limit length for readability
148
+ errorMessage = errorBody.length > 100 ?
149
+ errorBody.substring(0, 100) + '...' :
150
+ errorBody;
151
+ }
152
+ else {
153
+ errorMessage = `API error: ${response.status} ${response.statusText}`;
154
+ }
155
+ // Add status details if not already included
156
+ if (!errorMessage.includes(response.status.toString())) {
157
+ errorMessage = `${errorMessage} (Status: ${response.status})`;
158
+ }
159
+ console.log(`[callAI:${PACKAGE_VERSION}] Extracted text error message:`, errorMessage);
160
+ const error = new Error(errorMessage);
161
+ error.status = response.status;
162
+ error.statusText = response.statusText;
163
+ error.details = errorBody;
164
+ error.contentType = contentType;
165
+ throw error;
166
+ }
101
167
  }
102
- catch (error) {
103
- const textError = error;
104
- console.error(`[callAI:${PACKAGE_VERSION}] Error reading response body:`, textError);
105
- errorText = `Failed to read error details: ${textError.message || 'Unknown error'}`;
168
+ catch (responseError) {
169
+ if (responseError instanceof Error) {
170
+ // Re-throw if it's already properly formatted
171
+ throw responseError;
172
+ }
173
+ // Fallback error
174
+ const error = new Error(`API returned ${response.status}: ${response.statusText}`);
175
+ error.status = response.status;
176
+ error.statusText = response.statusText;
177
+ error.contentType = contentType;
178
+ throw error;
106
179
  }
107
- // Create a detailed error with status information
108
- console.log(`[callAI:${PACKAGE_VERSION}] Creating error object with status ${response.status}`);
109
- const errorMessage = `API returned error ${response.status}: ${response.statusText}`;
110
- const error = new Error(errorMessage);
111
- // Add extra properties for more context
112
- error.status = response.status;
113
- error.statusText = response.statusText;
114
- error.details = errorText;
115
- // Ensure this error is thrown and caught properly in the Promise chain
116
- console.error(`[callAI:${PACKAGE_VERSION}] THROWING API ERROR:`, {
117
- message: errorMessage,
118
- status: response.status,
119
- statusText: response.statusText,
120
- details: errorText
121
- });
122
- // This MUST throw the error from the promise
123
- return Promise.reject(error);
124
180
  }
125
181
  // Only if response is OK, create and return the streaming generator
126
182
  console.log(`[callAI:${PACKAGE_VERSION}] Response OK, creating streaming generator`);
@@ -362,7 +418,7 @@ async function callAINonStreaming(prompt, options = {}, isRetry = false) {
362
418
  const { endpoint, requestOptions, model, schemaStrategy } = prepareRequestParams(prompt, options);
363
419
  const response = await fetch(endpoint, requestOptions);
364
420
  // Handle HTTP errors, with potential fallback for invalid model
365
- if (!response.ok) {
421
+ if (!response.ok || response.status >= 400) {
366
422
  const { isInvalidModel } = await checkForInvalidModelError(response, model, isRetry, options.skipRetry);
367
423
  if (isInvalidModel) {
368
424
  // Retry with fallback model
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "call-ai",
3
- "version": "0.7.0-dev-preview-10",
3
+ "version": "0.7.0-dev-preview-13",
4
4
  "description": "Lightweight library for making AI API calls with streaming support",
5
5
  "main": "dist/index.js",
6
6
  "browser": "dist/index.js",