call-ai 0.8.4 → 0.8.5-dev-preview
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-core.d.ts +40 -0
- package/dist/api-core.js +313 -0
- package/dist/api.d.ts +2 -0
- package/dist/api.js +148 -480
- package/dist/error-handling.d.ts +12 -0
- package/dist/error-handling.js +176 -0
- package/dist/image.js +9 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -2
- package/dist/key-management.d.ts +43 -0
- package/dist/key-management.js +312 -0
- package/dist/non-streaming.d.ts +10 -0
- package/dist/non-streaming.js +265 -0
- package/dist/response-metadata.d.ts +18 -0
- package/dist/response-metadata.js +44 -0
- package/dist/strategies/model-strategies.js +2 -2
- package/dist/streaming.d.ts +7 -0
- package/dist/streaming.js +483 -0
- package/dist/types.d.ts +40 -0
- package/package.json +12 -13
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core API implementation for call-ai
|
|
3
|
+
*/
|
|
4
|
+
import { CallAIOptions, Message, StreamResponse, ThenableStreamResponse } from "./types";
|
|
5
|
+
declare const PACKAGE_VERSION: any;
|
|
6
|
+
/**
|
|
7
|
+
* Main API interface function for making AI API calls
|
|
8
|
+
*
|
|
9
|
+
* @param prompt The prompt to send to the AI, either a string or a Message array
|
|
10
|
+
* @param options Configuration options for the API call
|
|
11
|
+
* @returns Promise<string> for non-streaming or AsyncGenerator for streaming
|
|
12
|
+
*/
|
|
13
|
+
declare function callAI(prompt: string | Message[], options?: CallAIOptions): ThenableStreamResponse | Promise<string>;
|
|
14
|
+
/**
|
|
15
|
+
* Buffers the results of a streaming generator into a single string
|
|
16
|
+
*
|
|
17
|
+
* @param generator The streaming generator returned by callAI
|
|
18
|
+
* @returns Promise<string> with the complete response
|
|
19
|
+
*/
|
|
20
|
+
declare function bufferStreamingResults(generator: AsyncGenerator<string, string, unknown>): Promise<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Create a proxy that acts both as a Promise and an AsyncGenerator for backward compatibility
|
|
23
|
+
* @internal This is for internal use only, not part of public API
|
|
24
|
+
*/
|
|
25
|
+
declare function createBackwardCompatStreamingProxy(promise: Promise<StreamResponse>): ThenableStreamResponse;
|
|
26
|
+
/**
|
|
27
|
+
* Validates and prepares request parameters for API calls
|
|
28
|
+
*
|
|
29
|
+
* @param prompt User prompt (string or Message array)
|
|
30
|
+
* @param options Call options
|
|
31
|
+
* @returns Validated and processed parameters including apiKey
|
|
32
|
+
*/
|
|
33
|
+
declare function prepareRequestParams(prompt: string | Message[], options?: CallAIOptions): {
|
|
34
|
+
messages: Message[] | {
|
|
35
|
+
role: string;
|
|
36
|
+
content: string;
|
|
37
|
+
}[];
|
|
38
|
+
apiKey: any;
|
|
39
|
+
};
|
|
40
|
+
export { callAI, bufferStreamingResults, createBackwardCompatStreamingProxy, prepareRequestParams, PACKAGE_VERSION, };
|
package/dist/api-core.js
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Core API implementation for call-ai
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PACKAGE_VERSION = void 0;
|
|
7
|
+
exports.callAI = callAI;
|
|
8
|
+
exports.bufferStreamingResults = bufferStreamingResults;
|
|
9
|
+
exports.createBackwardCompatStreamingProxy = createBackwardCompatStreamingProxy;
|
|
10
|
+
exports.prepareRequestParams = prepareRequestParams;
|
|
11
|
+
const key_management_1 = require("./key-management");
|
|
12
|
+
const non_streaming_1 = require("./non-streaming");
|
|
13
|
+
const streaming_1 = require("./streaming");
|
|
14
|
+
// Import package version for debugging
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
16
|
+
const PACKAGE_VERSION = require("../package.json").version;
|
|
17
|
+
exports.PACKAGE_VERSION = PACKAGE_VERSION;
|
|
18
|
+
/**
|
|
19
|
+
* Main API interface function for making AI API calls
|
|
20
|
+
*
|
|
21
|
+
* @param prompt The prompt to send to the AI, either a string or a Message array
|
|
22
|
+
* @param options Configuration options for the API call
|
|
23
|
+
* @returns Promise<string> for non-streaming or AsyncGenerator for streaming
|
|
24
|
+
*/
|
|
25
|
+
// Main API interface function - must match original signature exactly
|
|
26
|
+
function callAI(prompt, options = {}) {
|
|
27
|
+
// Use the global debug flag if not specified in options
|
|
28
|
+
const debug = options.debug === undefined ? key_management_1.globalDebug : options.debug;
|
|
29
|
+
// Validate and prepare parameters (including API key validation)
|
|
30
|
+
prepareRequestParams(prompt, options);
|
|
31
|
+
// Handle schema strategy based on model or explicitly provided strategy
|
|
32
|
+
let schemaStrategy = {
|
|
33
|
+
strategy: "none",
|
|
34
|
+
model: options.model || "openai/gpt-3.5-turbo",
|
|
35
|
+
prepareRequest: () => ({}),
|
|
36
|
+
processResponse: (response) => {
|
|
37
|
+
// If response is an object, stringify it to match expected test output
|
|
38
|
+
if (response && typeof response === "object") {
|
|
39
|
+
return JSON.stringify(response);
|
|
40
|
+
}
|
|
41
|
+
return response;
|
|
42
|
+
},
|
|
43
|
+
shouldForceStream: false,
|
|
44
|
+
};
|
|
45
|
+
// If a schema is provided, determine the appropriate strategy
|
|
46
|
+
if (options.schema) {
|
|
47
|
+
const model = options.model || "openai/gpt-3.5-turbo";
|
|
48
|
+
// Choose function calling strategy based on model
|
|
49
|
+
if (/claude/i.test(model) || /anthropic/i.test(model)) {
|
|
50
|
+
schemaStrategy = {
|
|
51
|
+
strategy: "tool_mode",
|
|
52
|
+
model,
|
|
53
|
+
shouldForceStream: false,
|
|
54
|
+
prepareRequest: (schema) => {
|
|
55
|
+
// Parse the schema to extract the function definition
|
|
56
|
+
let toolDef = {};
|
|
57
|
+
if (typeof schema === "string") {
|
|
58
|
+
try {
|
|
59
|
+
toolDef = JSON.parse(schema);
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
// If it's not valid JSON, we'll use it as a plain description
|
|
63
|
+
toolDef = { description: schema };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else if (schema) {
|
|
67
|
+
toolDef = schema;
|
|
68
|
+
}
|
|
69
|
+
// Build a tools array compatible with Claude's format
|
|
70
|
+
const tools = [
|
|
71
|
+
{
|
|
72
|
+
type: "function",
|
|
73
|
+
function: {
|
|
74
|
+
name: toolDef.name || "execute_function",
|
|
75
|
+
description: toolDef.description || "Execute a function",
|
|
76
|
+
parameters: toolDef.parameters || {
|
|
77
|
+
type: "object",
|
|
78
|
+
properties: {},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
];
|
|
83
|
+
return {
|
|
84
|
+
tools,
|
|
85
|
+
tool_choice: {
|
|
86
|
+
type: "function",
|
|
87
|
+
function: { name: tools[0].function.name },
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
processResponse: (response) => {
|
|
92
|
+
// Handle different response formats
|
|
93
|
+
if (typeof response === "string") {
|
|
94
|
+
return response;
|
|
95
|
+
}
|
|
96
|
+
// Handle direct tool_use format
|
|
97
|
+
if (response && response.type === "tool_use") {
|
|
98
|
+
return response.input || "{}";
|
|
99
|
+
}
|
|
100
|
+
// Handle object with tool_use property
|
|
101
|
+
if (response && response.tool_use) {
|
|
102
|
+
return response.tool_use.input || "{}";
|
|
103
|
+
}
|
|
104
|
+
// Handle array of tool calls (OpenAI format)
|
|
105
|
+
if (Array.isArray(response)) {
|
|
106
|
+
if (response.length > 0 &&
|
|
107
|
+
response[0].function &&
|
|
108
|
+
response[0].function.arguments) {
|
|
109
|
+
return response[0].function.arguments;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// For all other cases, return string representation
|
|
113
|
+
return typeof response === "string"
|
|
114
|
+
? response
|
|
115
|
+
: JSON.stringify(response);
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
// For OpenAI compatible models, use json_schema format
|
|
121
|
+
schemaStrategy = {
|
|
122
|
+
strategy: "json_schema",
|
|
123
|
+
model,
|
|
124
|
+
shouldForceStream: false,
|
|
125
|
+
prepareRequest: (schema) => {
|
|
126
|
+
// Create a properly formatted JSON schema request
|
|
127
|
+
const schemaObj = schema || {};
|
|
128
|
+
return {
|
|
129
|
+
response_format: {
|
|
130
|
+
type: "json_schema",
|
|
131
|
+
json_schema: {
|
|
132
|
+
name: schemaObj.name || "result",
|
|
133
|
+
schema: {
|
|
134
|
+
type: "object",
|
|
135
|
+
properties: schemaObj.properties || {},
|
|
136
|
+
required: schemaObj.required ||
|
|
137
|
+
Object.keys(schemaObj.properties || {}),
|
|
138
|
+
additionalProperties: schemaObj.additionalProperties !== undefined
|
|
139
|
+
? schemaObj.additionalProperties
|
|
140
|
+
: false,
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
},
|
|
146
|
+
processResponse: (response) => {
|
|
147
|
+
// Handle different response formats
|
|
148
|
+
if (typeof response === "string") {
|
|
149
|
+
// Keep string responses as is
|
|
150
|
+
return response;
|
|
151
|
+
}
|
|
152
|
+
// If it's an object, convert to string to match test expectations
|
|
153
|
+
return JSON.stringify(response);
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// Check if this should be a streaming or non-streaming call
|
|
159
|
+
if (options.stream) {
|
|
160
|
+
if (debug) {
|
|
161
|
+
console.log(`[callAI:${PACKAGE_VERSION}] Making streaming request`);
|
|
162
|
+
}
|
|
163
|
+
// Handle streaming mode - return a Promise that resolves to an AsyncGenerator
|
|
164
|
+
// but also supports legacy non-awaited usage for backward compatibility
|
|
165
|
+
const streamPromise = (async () => {
|
|
166
|
+
// This exact pattern matches the original implementation in api.ts
|
|
167
|
+
return (0, streaming_1.callAIStreaming)(prompt, {
|
|
168
|
+
...options,
|
|
169
|
+
schemaStrategy,
|
|
170
|
+
});
|
|
171
|
+
})();
|
|
172
|
+
// Create a proxy object that acts both as a Promise and an AsyncGenerator for backward compatibility
|
|
173
|
+
// @ts-ignore - We're deliberately implementing a proxy with dual behavior
|
|
174
|
+
return createBackwardCompatStreamingProxy(streamPromise);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
if (debug) {
|
|
178
|
+
console.log(`[callAI:${PACKAGE_VERSION}] Making non-streaming request`);
|
|
179
|
+
}
|
|
180
|
+
// Pass schemaStrategy through options to avoid type error
|
|
181
|
+
const optionsWithSchema = {
|
|
182
|
+
...options,
|
|
183
|
+
schemaStrategy,
|
|
184
|
+
};
|
|
185
|
+
// Make a non-streaming API call
|
|
186
|
+
return (0, non_streaming_1.callAINonStreaming)(prompt, optionsWithSchema);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Buffers the results of a streaming generator into a single string
|
|
191
|
+
*
|
|
192
|
+
* @param generator The streaming generator returned by callAI
|
|
193
|
+
* @returns Promise<string> with the complete response
|
|
194
|
+
*/
|
|
195
|
+
async function bufferStreamingResults(generator) {
|
|
196
|
+
let result = "";
|
|
197
|
+
try {
|
|
198
|
+
// Iterate through the generator and collect results
|
|
199
|
+
for await (const chunk of generator) {
|
|
200
|
+
result += chunk;
|
|
201
|
+
}
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
// If we already collected some content, attach it to the error
|
|
206
|
+
if (error instanceof Error) {
|
|
207
|
+
const enhancedError = new Error(`${error.message} (Partial content: ${result.slice(0, 100)}...)`);
|
|
208
|
+
enhancedError.partialContent = result;
|
|
209
|
+
enhancedError.originalError = error;
|
|
210
|
+
throw enhancedError;
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
// For non-Error objects, create an Error with info
|
|
214
|
+
const newError = new Error(`Streaming error: ${String(error)}`);
|
|
215
|
+
newError.partialContent = result;
|
|
216
|
+
newError.originalError = error;
|
|
217
|
+
throw newError;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Create a proxy that acts both as a Promise and an AsyncGenerator for backward compatibility
|
|
223
|
+
* @internal This is for internal use only, not part of public API
|
|
224
|
+
*/
|
|
225
|
+
function createBackwardCompatStreamingProxy(promise) {
|
|
226
|
+
// Create a proxy that forwards methods to the Promise or AsyncGenerator as appropriate
|
|
227
|
+
return new Proxy({}, {
|
|
228
|
+
get(_target, prop) {
|
|
229
|
+
// First check if it's an AsyncGenerator method (needed for for-await)
|
|
230
|
+
if (prop === "next" ||
|
|
231
|
+
prop === "throw" ||
|
|
232
|
+
prop === "return" ||
|
|
233
|
+
prop === Symbol.asyncIterator) {
|
|
234
|
+
// Create wrapper functions that await the Promise first
|
|
235
|
+
if (prop === Symbol.asyncIterator) {
|
|
236
|
+
return function () {
|
|
237
|
+
return {
|
|
238
|
+
// Implement async iterator that gets the generator first
|
|
239
|
+
async next(value) {
|
|
240
|
+
try {
|
|
241
|
+
const generator = await promise;
|
|
242
|
+
return generator.next(value);
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
// Turn Promise rejection into iterator result with error thrown
|
|
246
|
+
return Promise.reject(error);
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
// Methods like next, throw, return
|
|
253
|
+
return async function (value) {
|
|
254
|
+
const generator = await promise;
|
|
255
|
+
return generator[prop](value);
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
// Then check if it's a Promise method
|
|
259
|
+
if (prop === "then" || prop === "catch" || prop === "finally") {
|
|
260
|
+
return promise[prop].bind(promise);
|
|
261
|
+
}
|
|
262
|
+
return undefined;
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Validates and prepares request parameters for API calls
|
|
268
|
+
*
|
|
269
|
+
* @param prompt User prompt (string or Message array)
|
|
270
|
+
* @param options Call options
|
|
271
|
+
* @returns Validated and processed parameters including apiKey
|
|
272
|
+
*/
|
|
273
|
+
function prepareRequestParams(prompt, options = {}) {
|
|
274
|
+
// Get API key from options or window.CALLAI_API_KEY (exactly matching original)
|
|
275
|
+
const apiKey = options.apiKey ||
|
|
276
|
+
(typeof window !== "undefined" ? window.CALLAI_API_KEY : null);
|
|
277
|
+
// Validate API key with original error message
|
|
278
|
+
if (!apiKey) {
|
|
279
|
+
throw new Error("API key is required. Provide it via options.apiKey or set window.CALLAI_API_KEY");
|
|
280
|
+
}
|
|
281
|
+
// Validate and process input parameters
|
|
282
|
+
if (!prompt || (typeof prompt !== "string" && !Array.isArray(prompt))) {
|
|
283
|
+
throw new Error(`Invalid prompt: ${prompt}. Must be a string or an array of message objects.`);
|
|
284
|
+
}
|
|
285
|
+
// Convert simple string prompts to message array format
|
|
286
|
+
const messages = Array.isArray(prompt)
|
|
287
|
+
? prompt
|
|
288
|
+
: [{ role: "user", content: prompt }];
|
|
289
|
+
// Validate message structure if array provided
|
|
290
|
+
if (Array.isArray(prompt)) {
|
|
291
|
+
for (const message of prompt) {
|
|
292
|
+
if (!message.role || !message.content) {
|
|
293
|
+
throw new Error(`Invalid message format. Each message must have 'role' and 'content' properties. Received: ${JSON.stringify(message)}`);
|
|
294
|
+
}
|
|
295
|
+
if (typeof message.role !== "string" ||
|
|
296
|
+
(typeof message.content !== "string" && !Array.isArray(message.content))) {
|
|
297
|
+
throw new Error(`Invalid message format. 'role' must be a string and 'content' must be a string or array. Received role: ${typeof message.role}, content: ${typeof message.content}`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// If provider-specific options are given, check for conflicts
|
|
302
|
+
if (options.provider &&
|
|
303
|
+
options.provider !== "auto" &&
|
|
304
|
+
options.model &&
|
|
305
|
+
!options.model.startsWith(options.provider + "/")) {
|
|
306
|
+
console.warn(`[callAI:${PACKAGE_VERSION}] WARNING: Specified provider '${options.provider}' doesn't match model '${options.model}'. Using model as specified.`);
|
|
307
|
+
}
|
|
308
|
+
// Return the validated parameters including API key
|
|
309
|
+
return {
|
|
310
|
+
messages,
|
|
311
|
+
apiKey,
|
|
312
|
+
};
|
|
313
|
+
}
|
package/dist/api.d.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Core API implementation for call-ai
|
|
3
3
|
*/
|
|
4
4
|
import { CallAIOptions, Message, StreamResponse } from "./types";
|
|
5
|
+
import { getMeta } from "./response-metadata";
|
|
6
|
+
export { getMeta };
|
|
5
7
|
/**
|
|
6
8
|
* Make an AI API call with the given options
|
|
7
9
|
* @param prompt User prompt as string or an array of message objects
|