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.
- package/dist/api.js +109 -53
- 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
|
-
//
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
//
|
|
96
|
-
console.log(`[callAI:${PACKAGE_VERSION}] Reading error response body...`);
|
|
97
|
-
let errorText = "";
|
|
98
|
+
// Extract error details from response
|
|
98
99
|
try {
|
|
99
|
-
|
|
100
|
-
|
|
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 (
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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