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 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', null, {
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
- for await (const chunk of response) {
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, null, {
47
+ const response = await callAI(messages, {
37
48
  apiKey: 'your-api-key',
38
49
  model: 'gpt-4'
39
50
  });
40
51
 
41
- // Non-streaming mode
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', schema, {
64
+ const response = await callAI('Summarize the benefits of exercise', {
62
65
  apiKey: 'your-api-key',
63
- stream: false
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', null, { apiKey: 'your-api-key' });
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', null, { apiKey });
114
+ const response = await callAI('Hello', { apiKey });
112
115
  ```
113
116
 
114
117
  ## API
115
118
 
116
119
  ```typescript
117
120
  // Main function
118
- async function* callAI(
121
+ function callAI(
119
122
  prompt: string | Message[],
120
- schema: Schema | null = null,
121
- options: Record<string, any> = {}
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: true)
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 schema Optional JSON schema for structured output
37
- * @param options Configuration options
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[], schema?: Schema | null, options?: Record<string, any>): AsyncGenerator<string, string, unknown>;
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 schema Optional JSON schema for structured output
14
- * @param options Configuration options
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
- async function* callAI(prompt, schema = null, options = {}) {
17
- try {
18
- const apiKey = options.apiKey || (typeof window !== 'undefined' ? window.CALLAI_API_KEY : null);
19
- const model = options.model || 'openrouter/auto';
20
- const endpoint = options.endpoint || 'https://openrouter.ai/api/v1/chat/completions';
21
- if (!apiKey) {
22
- throw new Error('API key is required. Provide it via options.apiKey or set window.CALLAI_API_KEY');
23
- }
24
- // Handle both string prompts and message arrays for backward compatibility
25
- const messages = Array.isArray(prompt)
26
- ? prompt
27
- : [{ role: 'user', content: prompt }];
28
- const requestOptions = {
29
- method: 'POST',
30
- headers: {
31
- 'Authorization': `Bearer ${apiKey}`,
32
- 'Content-Type': 'application/json'
33
- },
34
- body: JSON.stringify({
35
- model: model,
36
- stream: options.stream !== false, // Default to streaming
37
- messages: messages,
38
- // For schema requests, add provider requirement to ensure JSON schema support
39
- ...(schema && { provider: { require_parameters: true } }),
40
- // Pass through any additional options like temperature, but exclude internal keys
41
- ...Object.fromEntries(Object.entries(options).filter(([key]) => !['apiKey', 'model', 'endpoint'].includes(key))),
42
- // Handle schema if provided
43
- ...(schema && { response_format: {
44
- type: 'json_schema',
45
- json_schema: {
46
- name: schema.name || 'response',
47
- strict: true,
48
- schema: {
49
- type: 'object',
50
- properties: schema.properties || {},
51
- required: schema.required || Object.keys(schema.properties || {}),
52
- additionalProperties: schema.additionalProperties !== undefined
53
- ? schema.additionalProperties
54
- : false
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();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "call-ai",
3
- "version": "0.1.5",
3
+ "version": "0.2.0",
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",