call-ai 0.7.0-dev-preview-6 → 0.7.0-dev-preview-8

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.d.ts CHANGED
@@ -7,6 +7,7 @@ import { CallAIOptions, Message, StreamResponse } from "./types";
7
7
  * @param prompt User prompt as string or an array of message objects
8
8
  * @param options Configuration options including optional schema for structured output
9
9
  * @returns A Promise that resolves to the complete response string when streaming is disabled,
10
- * or an AsyncGenerator that yields partial responses when streaming is enabled
10
+ * or a Promise that resolves to an AsyncGenerator when streaming is enabled.
11
+ * The AsyncGenerator yields partial responses as they arrive.
11
12
  */
12
13
  export declare function callAI(prompt: string | Message[], options?: CallAIOptions): Promise<string | StreamResponse>;
package/dist/api.js CHANGED
@@ -12,7 +12,8 @@ const FALLBACK_MODEL = "openrouter/auto";
12
12
  * @param prompt User prompt as string or an array of message objects
13
13
  * @param options Configuration options including optional schema for structured output
14
14
  * @returns A Promise that resolves to the complete response string when streaming is disabled,
15
- * or an AsyncGenerator that yields partial responses when streaming is enabled
15
+ * or a Promise that resolves to an AsyncGenerator when streaming is enabled.
16
+ * The AsyncGenerator yields partial responses as they arrive.
16
17
  */
17
18
  function callAI(prompt, options = {}) {
18
19
  // Check if we need to force streaming based on model strategy
@@ -27,19 +28,45 @@ function callAI(prompt, options = {}) {
27
28
  return callAINonStreaming(prompt, options);
28
29
  }
29
30
  // Handle streaming mode - return a Promise that resolves to an AsyncGenerator
30
- return (async () => {
31
+ // but also supports legacy non-awaited usage for backward compatibility
32
+ const streamPromise = (async () => {
31
33
  // Do setup and validation before returning the generator
32
34
  const { endpoint, requestOptions, model, schemaStrategy } = prepareRequestParams(prompt, { ...options, stream: true });
33
35
  // Make the fetch request and handle errors before creating the generator
34
- const response = await fetch(endpoint, requestOptions);
35
- // Enhanced error handling with more debugging
36
+ console.log(`[callAI:${PACKAGE_VERSION}] Making fetch request to: ${endpoint}`);
37
+ console.log(`[callAI:${PACKAGE_VERSION}] With model: ${model}`);
38
+ let response;
39
+ try {
40
+ response = await fetch(endpoint, requestOptions);
41
+ console.log(`[callAI:${PACKAGE_VERSION}] Fetch completed with status:`, response.status, response.statusText);
42
+ }
43
+ catch (fetchError) {
44
+ console.error(`[callAI:${PACKAGE_VERSION}] Network error during fetch:`, fetchError);
45
+ throw fetchError; // Re-throw network errors
46
+ }
47
+ // Explicitly check for HTTP error status and log extensively
48
+ console.log(`[callAI:${PACKAGE_VERSION}] Response.ok =`, response.ok);
49
+ console.log(`[callAI:${PACKAGE_VERSION}] Response.status =`, response.status);
50
+ // Enhanced error handling with more debugging - MUST check !response.ok
36
51
  if (!response.ok) {
52
+ console.log(`[callAI:${PACKAGE_VERSION}] Detected error response with status:`, response.status);
37
53
  if (options.debug) {
38
54
  console.error(`[callAI:${PACKAGE_VERSION}] HTTP Error:`, response.status, response.statusText, response.url);
39
55
  }
40
56
  // Check if this is an invalid model error
41
- const { isInvalidModel, errorData } = await checkForInvalidModelError(response.clone(), // Clone response since we'll need to read body twice
42
- model, false, options.skipRetry);
57
+ console.log(`[callAI:${PACKAGE_VERSION}] Checking for invalid model error...`);
58
+ let isInvalidModel = false;
59
+ let errorData = null;
60
+ try {
61
+ const result = await checkForInvalidModelError(response.clone(), // Clone response since we'll need to read body twice
62
+ model, false, options.skipRetry);
63
+ isInvalidModel = result.isInvalidModel;
64
+ errorData = result.errorData;
65
+ console.log(`[callAI:${PACKAGE_VERSION}] Invalid model check result:`, isInvalidModel);
66
+ }
67
+ catch (checkError) {
68
+ console.error(`[callAI:${PACKAGE_VERSION}] Error during invalid model check:`, checkError);
69
+ }
43
70
  if (isInvalidModel && !options.skipRetry) {
44
71
  if (options.debug) {
45
72
  console.log(`[callAI:${PACKAGE_VERSION}] Retrying with fallback model: ${FALLBACK_MODEL}`);
@@ -49,11 +76,19 @@ function callAI(prompt, options = {}) {
49
76
  return result;
50
77
  }
51
78
  // Get full error text from body
52
- const errorText = await response.text();
53
- if (options.debug) {
54
- console.error(`[callAI:${PACKAGE_VERSION}] Error response body:`, errorText);
79
+ console.log(`[callAI:${PACKAGE_VERSION}] Reading error response body...`);
80
+ let errorText = "";
81
+ try {
82
+ errorText = await response.text();
83
+ console.log(`[callAI:${PACKAGE_VERSION}] Error response body:`, errorText);
84
+ }
85
+ catch (error) {
86
+ const textError = error;
87
+ console.error(`[callAI:${PACKAGE_VERSION}] Error reading response body:`, textError);
88
+ errorText = `Failed to read error details: ${textError.message || 'Unknown error'}`;
55
89
  }
56
90
  // Create a detailed error with status information
91
+ console.log(`[callAI:${PACKAGE_VERSION}] Creating error object with status ${response.status}`);
57
92
  const errorMessage = `API returned error ${response.status}: ${response.statusText}`;
58
93
  const error = new Error(errorMessage);
59
94
  // Add extra properties for more context
@@ -61,14 +96,28 @@ function callAI(prompt, options = {}) {
61
96
  error.statusText = response.statusText;
62
97
  error.details = errorText;
63
98
  // Ensure this error is thrown and caught properly in the Promise chain
64
- if (options.debug) {
65
- console.error(`[callAI:${PACKAGE_VERSION}] Throwing error:`, error);
66
- }
67
- throw error;
99
+ console.error(`[callAI:${PACKAGE_VERSION}] THROWING API ERROR:`, {
100
+ message: errorMessage,
101
+ status: response.status,
102
+ statusText: response.statusText,
103
+ details: errorText
104
+ });
105
+ // This MUST throw the error from the promise
106
+ return Promise.reject(error);
68
107
  }
69
108
  // Only if response is OK, create and return the streaming generator
109
+ console.log(`[callAI:${PACKAGE_VERSION}] Response OK, creating streaming generator`);
70
110
  return createStreamingGenerator(response, options, schemaStrategy, model);
71
111
  })();
112
+ // For backward compatibility with v0.6.x where users didn't await the result
113
+ if (process.env.NODE_ENV !== 'production') {
114
+ console.warn(`[callAI:${PACKAGE_VERSION}] WARNING: Using callAI with streaming without await is deprecated. ` +
115
+ `Please use 'const generator = await callAI(...)' instead of 'const generator = callAI(...)'. ` +
116
+ `This backward compatibility will be removed in a future version.`);
117
+ }
118
+ // Create a proxy object that acts both as a Promise and an AsyncGenerator for backward compatibility
119
+ // @ts-ignore - We're deliberately implementing a proxy with dual behavior
120
+ return createBackwardCompatStreamingProxy(streamPromise);
72
121
  }
73
122
  /**
74
123
  * Buffer streaming results into a single response for cases where
@@ -96,6 +145,51 @@ async function bufferStreamingResults(prompt, options) {
96
145
  handleApiError(error, "Streaming buffer error", options.debug);
97
146
  }
98
147
  }
148
+ /**
149
+ * Standardized API error handler
150
+ */
151
+ /**
152
+ * Create a proxy that acts both as a Promise and an AsyncGenerator for backward compatibility
153
+ * @internal This is for internal use only, not part of public API
154
+ */
155
+ function createBackwardCompatStreamingProxy(promise) {
156
+ // Create a proxy that forwards methods to the Promise or AsyncGenerator as appropriate
157
+ return new Proxy({}, {
158
+ get(target, prop) {
159
+ // First check if it's an AsyncGenerator method (needed for for-await)
160
+ if (prop === 'next' || prop === 'throw' || prop === 'return' || prop === Symbol.asyncIterator) {
161
+ // Create wrapper functions that await the Promise first
162
+ if (prop === Symbol.asyncIterator) {
163
+ return function () {
164
+ return {
165
+ // Implement async iterator that gets the generator first
166
+ async next(value) {
167
+ try {
168
+ const generator = await promise;
169
+ return generator.next(value);
170
+ }
171
+ catch (error) {
172
+ // Turn Promise rejection into iterator result with error thrown
173
+ return Promise.reject(error);
174
+ }
175
+ }
176
+ };
177
+ };
178
+ }
179
+ // Methods like next, throw, return
180
+ return async function (value) {
181
+ const generator = await promise;
182
+ return generator[prop](value);
183
+ };
184
+ }
185
+ // Then check if it's a Promise method
186
+ if (prop === 'then' || prop === 'catch' || prop === 'finally') {
187
+ return promise[prop].bind(promise);
188
+ }
189
+ return undefined;
190
+ }
191
+ });
192
+ }
99
193
  /**
100
194
  * Standardized API error handler
101
195
  */
package/dist/types.d.ts CHANGED
@@ -68,6 +68,12 @@ export interface SchemaStrategy {
68
68
  * Return type for streaming API calls
69
69
  */
70
70
  export type StreamResponse = AsyncGenerator<string, string, unknown>;
71
+ /**
72
+ * @internal
73
+ * Internal type for backward compatibility with v0.6.x
74
+ * This type is not exposed in public API documentation
75
+ */
76
+ export type ThenableStreamResponse = AsyncGenerator<string, string, unknown> & Promise<StreamResponse>;
71
77
  export interface CallAIOptions {
72
78
  /**
73
79
  * API key for authentication
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "call-ai",
3
- "version": "0.7.0-dev-preview-6",
3
+ "version": "0.7.0-dev-preview-8",
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",