call-ai 0.1.5 → 0.2.0
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/README.md +36 -24
- package/dist/index.d.ts +5 -6
- package/dist/index.js +81 -54
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,13 +17,24 @@ pnpm add call-ai
|
|
|
17
17
|
```typescript
|
|
18
18
|
import { callAI } from 'call-ai';
|
|
19
19
|
|
|
20
|
-
// Basic usage with string prompt
|
|
21
|
-
const response = callAI('Explain quantum computing in simple terms',
|
|
20
|
+
// Basic usage with string prompt (non-streaming by default)
|
|
21
|
+
const response = await callAI('Explain quantum computing in simple terms', {
|
|
22
22
|
apiKey: 'your-api-key',
|
|
23
23
|
model: 'gpt-4'
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
// The response is the complete text
|
|
27
|
+
console.log(response);
|
|
28
|
+
|
|
29
|
+
// With streaming enabled (returns an AsyncGenerator)
|
|
30
|
+
const generator = callAI('Tell me a story', {
|
|
31
|
+
apiKey: 'your-api-key',
|
|
32
|
+
model: 'gpt-4',
|
|
33
|
+
stream: true
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Process streaming updates
|
|
37
|
+
for await (const chunk of generator) {
|
|
27
38
|
console.log(chunk); // Streaming updates as they arrive
|
|
28
39
|
}
|
|
29
40
|
|
|
@@ -33,20 +44,12 @@ const messages = [
|
|
|
33
44
|
{ role: 'user', content: 'Explain quantum computing in simple terms' }
|
|
34
45
|
];
|
|
35
46
|
|
|
36
|
-
const response = callAI(messages,
|
|
47
|
+
const response = await callAI(messages, {
|
|
37
48
|
apiKey: 'your-api-key',
|
|
38
49
|
model: 'gpt-4'
|
|
39
50
|
});
|
|
40
51
|
|
|
41
|
-
|
|
42
|
-
// With stream: false, the function returns the full string directly (not a generator)
|
|
43
|
-
const result = await callAI('Write a short poem', null, {
|
|
44
|
-
apiKey: 'your-api-key',
|
|
45
|
-
model: 'gpt-4',
|
|
46
|
-
stream: false
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
console.log(result);
|
|
52
|
+
console.log(response);
|
|
50
53
|
|
|
51
54
|
// Using schema for structured output
|
|
52
55
|
const schema = {
|
|
@@ -58,9 +61,9 @@ const schema = {
|
|
|
58
61
|
required: ['title', 'summary']
|
|
59
62
|
};
|
|
60
63
|
|
|
61
|
-
const response = await callAI('Summarize the benefits of exercise',
|
|
64
|
+
const response = await callAI('Summarize the benefits of exercise', {
|
|
62
65
|
apiKey: 'your-api-key',
|
|
63
|
-
|
|
66
|
+
schema: schema
|
|
64
67
|
});
|
|
65
68
|
|
|
66
69
|
const structuredOutput = JSON.parse(response);
|
|
@@ -69,7 +72,7 @@ console.log(structuredOutput.title);
|
|
|
69
72
|
|
|
70
73
|
## Features
|
|
71
74
|
|
|
72
|
-
- 🔄 Streaming responses via AsyncGenerator
|
|
75
|
+
- 🔄 Streaming responses via AsyncGenerator when `stream: true`
|
|
73
76
|
- 🧩 Structured JSON outputs with schema validation
|
|
74
77
|
- 🔌 Compatible with OpenRouter and OpenAI API formats
|
|
75
78
|
- 📝 Support for message arrays with system, user, and assistant roles
|
|
@@ -94,13 +97,13 @@ You can provide your API key in three ways:
|
|
|
94
97
|
|
|
95
98
|
1. Directly in the options:
|
|
96
99
|
```typescript
|
|
97
|
-
const response = callAI('Hello',
|
|
100
|
+
const response = await callAI('Hello', { apiKey: 'your-api-key' });
|
|
98
101
|
```
|
|
99
102
|
|
|
100
103
|
2. Set globally in the browser:
|
|
101
104
|
```typescript
|
|
102
105
|
window.CALLAI_API_KEY = 'your-api-key';
|
|
103
|
-
const response = callAI('Hello');
|
|
106
|
+
const response = await callAI('Hello');
|
|
104
107
|
```
|
|
105
108
|
|
|
106
109
|
3. Use environment variables in Node.js (with a custom implementation):
|
|
@@ -108,18 +111,17 @@ const response = callAI('Hello');
|
|
|
108
111
|
// Example of environment variable integration
|
|
109
112
|
import { callAI } from 'call-ai';
|
|
110
113
|
const apiKey = process.env.OPENAI_API_KEY || process.env.OPENROUTER_API_KEY;
|
|
111
|
-
const response = callAI('Hello',
|
|
114
|
+
const response = await callAI('Hello', { apiKey });
|
|
112
115
|
```
|
|
113
116
|
|
|
114
117
|
## API
|
|
115
118
|
|
|
116
119
|
```typescript
|
|
117
120
|
// Main function
|
|
118
|
-
|
|
121
|
+
function callAI(
|
|
119
122
|
prompt: string | Message[],
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
): AsyncGenerator<string, string, unknown>
|
|
123
|
+
options?: CallAIOptions
|
|
124
|
+
): Promise<string> | AsyncGenerator<string, string, unknown>
|
|
123
125
|
|
|
124
126
|
// Types
|
|
125
127
|
type Message = {
|
|
@@ -133,6 +135,15 @@ interface Schema {
|
|
|
133
135
|
required?: string[];
|
|
134
136
|
additionalProperties?: boolean;
|
|
135
137
|
}
|
|
138
|
+
|
|
139
|
+
interface CallAIOptions {
|
|
140
|
+
apiKey?: string;
|
|
141
|
+
model?: string;
|
|
142
|
+
endpoint?: string;
|
|
143
|
+
stream?: boolean;
|
|
144
|
+
schema?: Schema | null;
|
|
145
|
+
[key: string]: any;
|
|
146
|
+
}
|
|
136
147
|
```
|
|
137
148
|
|
|
138
149
|
### Options
|
|
@@ -140,7 +151,8 @@ interface Schema {
|
|
|
140
151
|
* `apiKey`: Your API key (can also be set via window.CALLAI_API_KEY)
|
|
141
152
|
* `model`: Model identifier (default: 'openrouter/auto')
|
|
142
153
|
* `endpoint`: API endpoint (default: 'https://openrouter.ai/api/v1/chat/completions')
|
|
143
|
-
* `stream`: Enable streaming responses (default:
|
|
154
|
+
* `stream`: Enable streaming responses (default: false)
|
|
155
|
+
* `schema`: Optional JSON schema for structured output
|
|
144
156
|
* Any other options are passed directly to the API (temperature, max_tokens, etc.)
|
|
145
157
|
|
|
146
158
|
## License
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ export interface CallAIOptions {
|
|
|
16
16
|
model?: string;
|
|
17
17
|
endpoint?: string;
|
|
18
18
|
stream?: boolean;
|
|
19
|
+
schema?: Schema | null;
|
|
19
20
|
[key: string]: any;
|
|
20
21
|
}
|
|
21
22
|
export interface AIResponse {
|
|
@@ -27,13 +28,11 @@ export interface AIResponse {
|
|
|
27
28
|
};
|
|
28
29
|
model: string;
|
|
29
30
|
}
|
|
30
|
-
/**
|
|
31
|
-
* Helper function for making OpenAI-compatible AI calls
|
|
32
|
-
*/
|
|
33
31
|
/**
|
|
34
32
|
* Make an AI API call with the given options
|
|
35
33
|
* @param prompt User prompt as string or an array of message objects
|
|
36
|
-
* @param
|
|
37
|
-
* @
|
|
34
|
+
* @param options Configuration options including optional schema for structured output
|
|
35
|
+
* @returns A Promise that resolves to the complete response string when streaming is disabled,
|
|
36
|
+
* or an AsyncGenerator that yields partial responses when streaming is enabled
|
|
38
37
|
*/
|
|
39
|
-
export declare function callAI(prompt: string | Message[],
|
|
38
|
+
export declare function callAI(prompt: string | Message[], options?: CallAIOptions): Promise<string> | AsyncGenerator<string, string, unknown>;
|
package/dist/index.js
CHANGED
|
@@ -4,66 +4,93 @@
|
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.callAI = callAI;
|
|
7
|
-
/**
|
|
8
|
-
* Helper function for making OpenAI-compatible AI calls
|
|
9
|
-
*/
|
|
10
7
|
/**
|
|
11
8
|
* Make an AI API call with the given options
|
|
12
9
|
* @param prompt User prompt as string or an array of message objects
|
|
13
|
-
* @param
|
|
14
|
-
* @
|
|
10
|
+
* @param options Configuration options including optional schema for structured output
|
|
11
|
+
* @returns A Promise that resolves to the complete response string when streaming is disabled,
|
|
12
|
+
* or an AsyncGenerator that yields partial responses when streaming is enabled
|
|
15
13
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
14
|
+
function callAI(prompt, options = {}) {
|
|
15
|
+
// Handle non-streaming mode (default)
|
|
16
|
+
if (options.stream !== true) {
|
|
17
|
+
return callAINonStreaming(prompt, options);
|
|
18
|
+
}
|
|
19
|
+
// Handle streaming mode
|
|
20
|
+
return callAIStreaming(prompt, options);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Prepare request parameters common to both streaming and non-streaming calls
|
|
24
|
+
*/
|
|
25
|
+
function prepareRequestParams(prompt, options) {
|
|
26
|
+
const apiKey = options.apiKey || (typeof window !== 'undefined' ? window.CALLAI_API_KEY : null);
|
|
27
|
+
const model = options.model || 'openrouter/auto';
|
|
28
|
+
const endpoint = options.endpoint || 'https://openrouter.ai/api/v1/chat/completions';
|
|
29
|
+
const schema = options.schema || null;
|
|
30
|
+
if (!apiKey) {
|
|
31
|
+
throw new Error('API key is required. Provide it via options.apiKey or set window.CALLAI_API_KEY');
|
|
32
|
+
}
|
|
33
|
+
// Handle both string prompts and message arrays for backward compatibility
|
|
34
|
+
const messages = Array.isArray(prompt)
|
|
35
|
+
? prompt
|
|
36
|
+
: [{ role: 'user', content: prompt }];
|
|
37
|
+
const requestOptions = {
|
|
38
|
+
method: 'POST',
|
|
39
|
+
headers: {
|
|
40
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
41
|
+
'Content-Type': 'application/json'
|
|
42
|
+
},
|
|
43
|
+
body: JSON.stringify({
|
|
44
|
+
model: model,
|
|
45
|
+
stream: options.stream === true,
|
|
46
|
+
messages: messages,
|
|
47
|
+
// For schema requests, add provider requirement to ensure JSON schema support
|
|
48
|
+
...(schema && { provider: { require_parameters: true } }),
|
|
49
|
+
// Pass through any additional options like temperature, but exclude internal keys
|
|
50
|
+
...Object.fromEntries(Object.entries(options).filter(([key]) => !['apiKey', 'model', 'endpoint', 'stream', 'schema'].includes(key))),
|
|
51
|
+
// Handle schema if provided
|
|
52
|
+
...(schema && { response_format: {
|
|
53
|
+
type: 'json_schema',
|
|
54
|
+
json_schema: {
|
|
55
|
+
name: schema.name || 'response',
|
|
56
|
+
strict: true,
|
|
57
|
+
schema: {
|
|
58
|
+
type: 'object',
|
|
59
|
+
properties: schema.properties || {},
|
|
60
|
+
required: schema.required || Object.keys(schema.properties || {}),
|
|
61
|
+
additionalProperties: schema.additionalProperties !== undefined
|
|
62
|
+
? schema.additionalProperties
|
|
63
|
+
: false
|
|
56
64
|
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
}
|
|
65
|
+
}
|
|
66
|
+
} })
|
|
67
|
+
})
|
|
68
|
+
};
|
|
69
|
+
return { apiKey, model, endpoint, requestOptions };
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Internal implementation for non-streaming API calls
|
|
73
|
+
*/
|
|
74
|
+
async function callAINonStreaming(prompt, options = {}) {
|
|
75
|
+
try {
|
|
76
|
+
const { endpoint, requestOptions } = prepareRequestParams(prompt, options);
|
|
77
|
+
const response = await fetch(endpoint, requestOptions);
|
|
78
|
+
const result = await response.json();
|
|
79
|
+
const content = result.choices[0]?.message?.content || '';
|
|
80
|
+
return content;
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
console.error("AI call failed:", error);
|
|
84
|
+
return "Sorry, I couldn't process that request.";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Internal implementation for streaming API calls
|
|
89
|
+
*/
|
|
90
|
+
async function* callAIStreaming(prompt, options = {}) {
|
|
91
|
+
try {
|
|
92
|
+
const { endpoint, requestOptions } = prepareRequestParams(prompt, { ...options, stream: true });
|
|
60
93
|
const response = await fetch(endpoint, requestOptions);
|
|
61
|
-
// For non-streaming responses, return the full result
|
|
62
|
-
if (options.stream === false) {
|
|
63
|
-
const result = await response.json();
|
|
64
|
-
const content = result.choices[0]?.message?.content || '';
|
|
65
|
-
return content;
|
|
66
|
-
}
|
|
67
94
|
// Handle streaming response
|
|
68
95
|
const reader = response.body.getReader();
|
|
69
96
|
const decoder = new TextDecoder();
|