llmjs2 1.1.1 → 1.3.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
@@ -1,357 +1,382 @@
1
- # llmjs2
2
-
3
- A lightweight llm Node.js library for building simple / personal AI applications
4
-
5
- ## Supported Providers
6
-
7
- - **Ollama** - Connect to Ollama's cloud API
8
- - **OpenRouter** - Access multiple LLM models through OpenRouter
9
-
10
- ## Installation
11
-
12
- ```bash
13
- npm install llmjs2
14
- ```
15
-
16
- ## Usage
17
-
18
- llmjs2 supports three calling conventions:
19
-
20
- ### Simple API (Auto-Detection)
21
-
22
- ```javascript
23
- import { completion } from 'llmjs2';
24
-
25
- // Just provide a prompt - the library handles the rest
26
- const result = await completion('Explain the use of llmjs2');
27
-
28
- // Or provide a model and prompt
29
- const result = await completion('ollama/minimax-m2.5:cloud', 'Explain the use of llmjs2');
30
- ```
31
-
32
- **How it works:**
33
- - Looks for `OLLAMA_API_KEY` and `OPEN_ROUTER_API_KEY` environment variables
34
- - If only one is set, uses that provider
35
- - If both are set, randomly chooses one
36
- - Uses `OLLAMA_DEFAULT_MODEL` or defaults to `minimax-m2.5:cloud` for Ollama
37
- - Uses `OPEN_ROUTER_DEFAULT_MODEL` or defaults to `openrouter/free` for OpenRouter
38
- - If a model is provided, uses that model instead of the default
39
-
40
- ### Function-Based API
41
-
42
- ```javascript
43
- import { completion } from 'llmjs2';
44
-
45
- // Using Ollama
46
- const resultOllama = await completion('ollama/minimax-m2.5:cloud', 'Explain the use of llmjs2', 'your-api-key');
47
-
48
- // Using OpenRouter
49
- const resultOR = await completion('openrouter/openrouter/free', 'Explain the use of llmjs2', 'your-api-key');
50
- ```
51
-
52
- ### Object-Based API
53
-
54
- ```javascript
55
- import { completion } from 'llmjs2';
56
-
57
- // Using Ollama with system message
58
- const resultOllama = await completion({
59
- model: 'ollama/minimax-m2.5:cloud',
60
- messages: [
61
- { role: 'system', content: 'You are a helpful AI assistant.' },
62
- { role: 'user', content: 'Explain the use of llmjs2.' }
63
- ],
64
- apiKey: 'your-api-key' // optional
65
- });
66
-
67
- // Using OpenRouter with system message
68
- const resultOR = await completion({
69
- model: 'openrouter/openrouter/free',
70
- messages: [
71
- { role: 'system', content: 'You are a helpful AI assistant.' },
72
- { role: 'user', content: 'Explain the use of llmjs2.' }
73
- ],
74
- apiKey: 'your-api-key' // optional
75
- });
76
- ```
77
-
78
- ## Tools Support
79
-
80
- llmjs2 supports function calling (tools) through the object-based API:
81
-
82
- ```javascript
83
- import { completion } from 'llmjs2';
84
-
85
- const result = await completion({
86
- model: 'openrouter/openrouter/free',
87
- messages: [
88
- { role: 'user', content: 'What is the weather like in Paris?' }
89
- ],
90
- tools: [
91
- {
92
- type: 'function',
93
- function: {
94
- name: 'get_weather',
95
- description: 'Get the current weather in a given location',
96
- parameters: {
97
- type: 'object',
98
- properties: {
99
- location: {
100
- type: 'string',
101
- description: 'The city and state, e.g. San Francisco, CA'
102
- },
103
- unit: {
104
- type: 'string',
105
- enum: ['celsius', 'fahrenheit'],
106
- description: 'The temperature unit to use'
107
- }
108
- },
109
- required: ['location']
110
- }
111
- }
112
- }
113
- ]
114
- });
115
-
116
- // Result when tools are used:
117
- // {
118
- // content: '',
119
- // tool_calls: [
120
- // {
121
- // id: 'call_123',
122
- // type: 'function',
123
- // function: {
124
- // name: 'get_weather',
125
- // arguments: '{"location": "Paris, France"}'
126
- // }
127
- // }
128
- // ]
129
- // }
130
- ```
131
-
132
- ## API Key Configuration
133
-
134
- You can provide API keys in four ways:
135
-
136
- ### 1. Simple API (Environment Variables)
137
-
138
- ```bash
139
- export OLLAMA_API_KEY=your-ollama-api-key
140
- export OPEN_ROUTER_API_KEY=your-openrouter-api-key
141
-
142
- # Optional: Set default models
143
- export OLLAMA_DEFAULT_MODEL=minimax-m2.5:cloud
144
- export OPEN_ROUTER_DEFAULT_MODEL=openrouter/free
145
- ```
146
-
147
- ```javascript
148
- const result = await completion('Your prompt');
149
- ```
150
-
151
- ### 2. Direct Parameter (Function API)
152
-
153
- ```javascript
154
- const result = await completion('ollama/minimax-m2.5:cloud', 'Your prompt', 'your-api-key');
155
- ```
156
-
157
- ### 3. Object Property (Object API)
158
-
159
- ```javascript
160
- const result = await completion({
161
- model: 'ollama/minimax-m2.5:cloud',
162
- messages: [{ role: 'user', content: 'Your prompt' }],
163
- apiKey: 'your-api-key'
164
- });
165
- ```
166
-
167
- ### 4. Environment Variables (Function/Object API)
168
-
169
- ```bash
170
- export OLLAMA_API_KEY=your-ollama-api-key
171
- export OPEN_ROUTER_API_KEY=your-openrouter-api-key
172
- ```
173
-
174
- ```javascript
175
- // Function API
176
- const result = await completion('ollama/minimax-m2.5:cloud', 'Your prompt');
177
-
178
- // Object API
179
- const result = await completion({
180
- model: 'ollama/minimax-m2.5:cloud',
181
- messages: [{ role: 'user', content: 'Your prompt' }]
182
- });
183
- ```
184
-
185
- ## Model Format
186
-
187
- Models must be specified in the format: `provider/model_name`
188
-
189
- The provider is the text before the first `/`, and the model name is everything after it.
190
-
191
- Examples:
192
- - `ollama/minimax-m2.5:cloud`
193
- - `ollama/llama2`
194
- - `openrouter/openrouter/free`
195
- - `openrouter/meta-llama/llama-2-70b-chat`
196
-
197
- ## Messages Format (Object API)
198
-
199
- The `messages` parameter is an array of message objects with the following structure:
200
-
201
- ```javascript
202
- [
203
- { role: 'system', content: 'You are a helpful AI assistant.' },
204
- { role: 'user', content: 'What is the capital of France?' },
205
- { role: 'assistant', content: 'The capital of France is Paris.' },
206
- { role: 'user', content: 'What is its population?' }
207
- ]
208
- ```
209
-
210
- **Supported roles:**
211
- - `system` - System instructions
212
- - `user` - User messages
213
- - `assistant` - Assistant responses
214
-
215
- ## Tools Format (Object API)
216
-
217
- The `tools` parameter is an array of tool definitions:
218
-
219
- ```javascript
220
- [
221
- {
222
- type: 'function',
223
- function: {
224
- name: 'function_name',
225
- description: 'Description of what the function does',
226
- parameters: {
227
- type: 'object',
228
- properties: {
229
- param1: {
230
- type: 'string',
231
- description: 'Description of parameter'
232
- }
233
- },
234
- required: ['param1']
235
- }
236
- }
237
- }
238
- ]
239
- ```
240
-
241
- ## Error Handling
242
-
243
- The library throws descriptive errors for:
244
- - Missing or invalid parameters
245
- - Missing API keys
246
- - API request failures
247
- - Invalid response formats
248
- - Request timeouts (60 seconds)
249
- - Invalid tools format
250
-
251
- ```javascript
252
- try {
253
- const result = await completion('Your prompt');
254
- } catch (error) {
255
- console.error('Completion failed:', error.message);
256
- }
257
- ```
258
-
259
- ## Example Programs
260
-
261
- ### Main Example
262
-
263
- A real usage test program is included in `example.js`. To run it:
264
-
265
- ```bash
266
- # Set your API keys
267
- export OLLAMA_API_KEY=your-ollama-api-key
268
- export OPEN_ROUTER_API_KEY=your-openrouter-api-key
269
-
270
- # Run the example
271
- node example.js
272
- ```
273
-
274
- The example program will:
275
- - Test simple API (auto-detection)
276
- - Test simple API with model
277
- - Test Ollama with function-based API
278
- - Test Ollama with object-based API
279
- - Test Ollama with tools
280
- - Test OpenRouter with function-based API
281
- - Test OpenRouter with object-based API
282
- - Test OpenRouter with tools
283
- - Display results and test summary
284
-
285
-
286
-
287
- ## API Reference
288
-
289
- ### completion(prompt)
290
-
291
- **Simple API (Prompt Only)**
292
-
293
- **Parameters:**
294
- - `prompt` (string): The prompt to send to the LLM
295
-
296
- **Returns:**
297
- - `Promise<string>`: The completion result
298
-
299
- **Behavior:**
300
- - Auto-detects provider based on available API keys
301
- - Uses `OLLAMA_DEFAULT_MODEL` or defaults to `minimax-m2.5:cloud` for Ollama
302
- - Uses `OPEN_ROUTER_DEFAULT_MODEL` or defaults to `openrouter/free` for OpenRouter
303
- - Randomly chooses provider if both API keys are set
304
-
305
- ### completion(model, prompt)
306
-
307
- **Simple API (Model and Prompt)**
308
-
309
- **Parameters:**
310
- - `model` (string): Model identifier in format "provider/model_name"
311
- - `prompt` (string): The prompt to send to the LLM
312
-
313
- **Returns:**
314
- - `Promise<string>`: The completion result
315
-
316
- **Behavior:**
317
- - Auto-detects provider based on available API keys
318
- - Uses the provided model instead of the default
319
- - Randomly chooses provider if both API keys are set
320
-
321
- ### completion(model, prompt, apiKey)
322
-
323
- **Function-Based API**
324
-
325
- **Parameters:**
326
- - `model` (string): Model identifier in format "provider/model_name"
327
- - `prompt` (string): The prompt to send to the LLM
328
- - `apiKey` (string, optional): API key (falls back to environment variables)
329
-
330
- **Returns:**
331
- - `Promise<string>`: The completion result
332
-
333
- ### completion(options)
334
-
335
- **Object-Based API**
336
-
337
- **Parameters:**
338
- - `options` (object): Configuration object
339
- - `model` (string): Model identifier in format "provider/model_name"
340
- - `messages` (array): Array of message objects with role and content
341
- - `apiKey` (string, optional): API key (falls back to environment variables)
342
- - `tools` (array, optional): Array of tool definitions
343
-
344
- **Returns:**
345
- - `Promise<string|object>`: The completion result (string or object with tool calls)
346
-
347
- **Throws:**
348
- - Error if model format is invalid
349
- - Error if prompt/messages is missing
350
- - Error if API key is not provided
351
- - Error if API request fails
352
- - Error if request times out (60 seconds)
353
- - Error if tools format is invalid
354
-
355
- ## License
356
-
357
- MIT
1
+ # llmjs2
2
+
3
+ A unified, enterprise-grade Node.js library for connecting to multiple Large Language Model (LLM) providers: OpenAI, Ollama, and OpenRouter.
4
+
5
+ **Features:**
6
+ - **Unified API**: Single interface for OpenAI, Ollama, and OpenRouter
7
+ - **Intelligent Router**: Load balancing and multiple routing strategies
8
+ - **Guardrails System**: Content filtering, logging, rate limiting, and custom processing
9
+ - **OpenAI-Compatible Server**: Drop-in replacement for OpenAI API clients
10
+ - **CLI Interface**: Command-line server management with configuration files
11
+ - **Enterprise Security**: Input validation, error sanitization, and safe defaults
12
+ - **Zero External Dependencies**: Pure Node.js implementation
13
+
14
+ ## Features
15
+
16
+ - **Unified API**: Single interface for OpenAI, Ollama, and OpenRouter
17
+ - **Auto-detection**: Automatically chooses available providers based on API keys
18
+ - **Enterprise-grade**: Robust error handling, input validation, and security measures
19
+ - **Zero dependencies**: Uses only Node.js built-in modules
20
+ - **TypeScript-free**: Pure JavaScript, no compilation required
21
+ - **Production-ready**: Comprehensive testing and security auditing
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ npm install llmjs2
27
+ ```
28
+
29
+ Or for global CLI usage:
30
+
31
+ ```bash
32
+ npm install -g llmjs2
33
+ ```
34
+
35
+ ## Quick Test
36
+
37
+ Try the sample configuration:
38
+
39
+ ```bash
40
+ # Validate configuration
41
+ node validate-config.js
42
+
43
+ # Start server with sample config
44
+ node cli.js --config config.yaml --port 3001
45
+
46
+ # Test the API
47
+ curl -X POST http://localhost:3001/v1/chat/completions \
48
+ -H "Content-Type: application/json" \
49
+ -d '{"messages":[{"role":"user","content":"Hello!"}]}'
50
+
51
+ # Response format:
52
+ # {
53
+ # "id": "chatcmpl-123456",
54
+ # "object": "chat.completion",
55
+ # "created": 1640995200,
56
+ # "model": "ollama/minimax-m2.5:cloud",
57
+ # "messages": [
58
+ # {"role": "user", "content": "Hello!"},
59
+ # {"role": "assistant", "content": "Hi there!"}
60
+ # ]
61
+ # }
62
+ ```
63
+
64
+ See `CONFIG_README.md` for detailed configuration examples.
65
+
66
+ ## Quick Start
67
+
68
+ ```javascript
69
+ import { completion } from 'llmjs2';
70
+
71
+ // Set API keys
72
+ process.env.OPENAI_API_KEY = 'your-openai-key';
73
+ process.env.OLLAMA_API_KEY = 'your-ollama-key';
74
+ process.env.OPEN_ROUTER_API_KEY = 'your-openrouter-key';
75
+
76
+ // Simple completion
77
+ const response = await completion('Hello, how are you?');
78
+ console.log(response);
79
+ ```
80
+
81
+ ## API Keys Setup
82
+
83
+ Set your API keys as environment variables:
84
+
85
+ ```bash
86
+ export OPENAI_API_KEY=your_openai_api_key
87
+ export OLLAMA_API_KEY=your_ollama_api_key
88
+ export OPEN_ROUTER_API_KEY=your_openrouter_api_key
89
+ ```
90
+
91
+ ## Usage Patterns
92
+
93
+ ### 1. Simple API (Auto-detection)
94
+
95
+ ```javascript
96
+ import { completion } from 'llmjs2';
97
+
98
+ const response = await completion('Explain quantum physics simply');
99
+ ```
100
+
101
+ ### 2. Provider-Specific Model
102
+
103
+ ```javascript
104
+ // OpenAI
105
+ const openaiResponse = await completion('openai/gpt-4', 'Write a haiku about coding');
106
+
107
+ // Ollama
108
+ const ollamaResponse = await completion('ollama/minimax-m2.5:cloud', 'What is AI?');
109
+
110
+ // OpenRouter
111
+ const openrouterResponse = await completion('openrouter/openrouter/free', 'Tell me a joke');
112
+ ```
113
+
114
+ ### 3. Advanced Object API
115
+
116
+ ```javascript
117
+ const response = await completion({
118
+ model: 'openai/gpt-3.5-turbo',
119
+ messages: [
120
+ { role: 'system', content: 'You are a helpful assistant.' },
121
+ { role: 'user', content: 'What is the capital of France?' }
122
+ ],
123
+ temperature: 0.7,
124
+ maxTokens: 100
125
+ });
126
+ ```
127
+
128
+ ## Configuration
129
+
130
+ ### Default Models
131
+
132
+ Set default models for each provider:
133
+
134
+ ```bash
135
+ export OPENAI_DEFAULT_MODEL=gpt-4
136
+ export OLLAMA_DEFAULT_MODEL=minimax-m2.5:cloud
137
+ export OPEN_ROUTER_DEFAULT_MODEL=openrouter/free
138
+ ```
139
+
140
+ ### Base URLs
141
+
142
+ Customize API endpoints:
143
+
144
+ ```bash
145
+ export OPENAI_BASE_URL=https://api.openai.com/v1
146
+ export OLLAMA_BASE_URL=https://ollama.com/api/chat
147
+ export OPEN_ROUTER_BASE_URL=https://openrouter.ai/api/v1/chat/completions
148
+ ```
149
+
150
+ ## Error Handling
151
+
152
+ ```javascript
153
+ import { completion } from 'llmjs2';
154
+
155
+ try {
156
+ const response = await completion('Tell me a joke');
157
+ console.log(response);
158
+ } catch (error) {
159
+ console.error('Error:', error.message);
160
+ }
161
+ ```
162
+
163
+ ## Conversations
164
+
165
+ ```javascript
166
+ import { completion } from 'llmjs2';
167
+
168
+ const messages = [
169
+ { role: 'system', content: 'You are a helpful coding assistant.' },
170
+ { role: 'user', content: 'How do I reverse a string in JavaScript?' }
171
+ ];
172
+
173
+ let response = await completion({ model: 'openai/gpt-4', messages });
174
+ console.log('Assistant:', response);
175
+
176
+ // Continue conversation
177
+ messages.push({ role: 'assistant', content: response });
178
+ messages.push({ role: 'user', content: 'Can you show me with an example?' });
179
+
180
+ response = await completion({ model: 'openai/gpt-4', messages });
181
+ console.log('Assistant:', response);
182
+ ```
183
+
184
+ ## Function Calling (Tools)
185
+
186
+ ```javascript
187
+ import { completion } from 'llmjs2';
188
+
189
+ const weatherTool = {
190
+ type: 'function',
191
+ function: {
192
+ name: 'get_weather',
193
+ description: 'Get current weather for a location',
194
+ parameters: {
195
+ type: 'object',
196
+ properties: {
197
+ location: { type: 'string', description: 'City name' }
198
+ },
199
+ required: ['location']
200
+ }
201
+ }
202
+ };
203
+
204
+ const response = await completion({
205
+ model: 'openai/gpt-4',
206
+ messages: [{ role: 'user', content: 'What is the weather in Paris?' }],
207
+ tools: [weatherTool]
208
+ });
209
+
210
+ if (response.tool_calls) {
211
+ console.log('Tool calls:', response.tool_calls);
212
+ }
213
+ ```
214
+
215
+ ## Router System
216
+
217
+ Intelligent model routing with load balancing and multiple strategies:
218
+
219
+ ```javascript
220
+ import { router } from 'llmjs2';
221
+
222
+ const modelList = [
223
+ {
224
+ model_name: 'gpt-3.5-turbo',
225
+ llm_params: {
226
+ model: 'ollama/chatgpt-v-2',
227
+ api_key: process.env.OLLAMA_API_KEY
228
+ }
229
+ },
230
+ {
231
+ model_name: 'gpt-3.5-turbo',
232
+ llm_params: {
233
+ model: 'openai/gpt-3.5-turbo',
234
+ api_key: process.env.OPENAI_API_KEY
235
+ }
236
+ }
237
+ ];
238
+
239
+ // Load balancing across models with same name
240
+ const route = router(modelList, 'random');
241
+ const response = await route.completion({
242
+ model: 'gpt-3.5-turbo',
243
+ messages: [{ role: 'user', content: 'Hello!' }]
244
+ });
245
+
246
+ // Auto-routing with different strategies
247
+ const randomRouter = router(modelList, 'random');
248
+ const sequentialRouter = router(modelList, 'sequential');
249
+ ```
250
+
251
+ **Routing Strategies:**
252
+ - `default`: Load balance across models with same name
253
+ - `random`: Randomly select from all models
254
+ - `sequential`: Cycle through models in order
255
+
256
+ ## Guardrails System
257
+
258
+ Add custom logic before and after LLM calls for content filtering, logging, and processing:
259
+
260
+ ```javascript
261
+ import { router } from 'llmjs2';
262
+
263
+ const route = router(modelList);
264
+
265
+ route.setGuardrails([
266
+ {
267
+ name: 'content_filter',
268
+ mode: 'pre_call',
269
+ code: (processId, input) => {
270
+ // Filter inappropriate content
271
+ const filteredMessages = input.messages.map(msg => ({
272
+ ...msg,
273
+ content: msg.content.replace(/badword/gi, '****')
274
+ }));
275
+ return { ...input, messages: filteredMessages };
276
+ }
277
+ },
278
+ {
279
+ name: 'response_logger',
280
+ mode: 'post_call',
281
+ code: (processId, result) => {
282
+ console.log(`[${processId}] Response:`, result);
283
+ return result;
284
+ }
285
+ }
286
+ ]);
287
+ ```
288
+
289
+ ## Server Mode
290
+
291
+ Run an API server that returns responses with metadata and message arrays:
292
+
293
+ ```javascript
294
+ import { router, app } from 'llmjs2';
295
+
296
+ const route = router(modelList);
297
+ app.use(route);
298
+ app.listen(3000);
299
+ ```
300
+
301
+ Or use the CLI:
302
+
303
+ ```bash
304
+ llmjs2 --config config.yaml --port 3000
305
+ ```
306
+
307
+ ## CLI Interface
308
+
309
+ Manage servers from the command line:
310
+
311
+ ```bash
312
+ # Start server with defaults
313
+ llmjs2
314
+
315
+ # Use configuration file
316
+ llmjs2 --config config.yaml
317
+
318
+ # Custom port and host
319
+ llmjs2 --port 8080 --host 0.0.0.0
320
+
321
+ # Get help
322
+ llmjs2 --help
323
+ ```
324
+
325
+ ## Configuration Files
326
+
327
+ Use YAML for advanced configuration:
328
+
329
+ ```yaml
330
+ model_list:
331
+ - model_name: premium
332
+ llm_params:
333
+ model: openrouter/openai/gpt-4
334
+ api_key: os.environ/OPEN_ROUTER_API_KEY
335
+
336
+ - model_name: standard
337
+ llm_params:
338
+ model: ollama/minimax-m2.5:cloud
339
+ api_key: os.environ/OLLAMA_API_KEY
340
+
341
+ guardrails:
342
+ - name: content_filter
343
+ mode: pre_call
344
+ code: |
345
+ (processId, input) => {
346
+ // Content filtering logic
347
+ return input;
348
+ }
349
+
350
+ router_settings:
351
+ routing_strategy: random
352
+ ```
353
+
354
+ **Note**: Model names in the configuration use the format `[provider]/[actual-model-name]` (e.g., `openai/gpt-4`, `ollama/minimax-m2.5:cloud`). The `[provider]/` prefix is used for routing and is automatically stripped when sending requests to LLM providers.
355
+
356
+ ## Security Features
357
+
358
+ - **No API key logging**: Sensitive information is never logged
359
+ - **Input validation**: All inputs are validated and sanitized
360
+ - **Error sanitization**: Error messages don't leak sensitive data
361
+ - **Timeout protection**: Requests timeout to prevent hanging
362
+ - **HTTPS only**: All communications use HTTPS
363
+
364
+ ## Testing
365
+
366
+ Run the test suite:
367
+
368
+ ```bash
369
+ npm test
370
+ ```
371
+
372
+ ## License
373
+
374
+ MIT
375
+
376
+ ## Contributing
377
+
378
+ Contributions welcome! Please ensure all tests pass and add tests for new features.
379
+
380
+ ## Support
381
+
382
+ For issues and questions, please create an issue on GitHub.