genai-lite 0.6.1 → 0.7.2

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.
Files changed (38) hide show
  1. package/README.md +21 -0
  2. package/dist/adapters/image/GenaiElectronImageAdapter.js +6 -4
  3. package/dist/adapters/image/OpenAIImageAdapter.js +5 -3
  4. package/dist/config/llm-presets.json +40 -44
  5. package/dist/image/ImageService.d.ts +1 -0
  6. package/dist/image/ImageService.js +13 -10
  7. package/dist/index.d.ts +6 -0
  8. package/dist/index.js +11 -1
  9. package/dist/llm/LLMService.d.ts +6 -0
  10. package/dist/llm/LLMService.js +20 -17
  11. package/dist/llm/clients/AnthropicClientAdapter.js +36 -15
  12. package/dist/llm/clients/GeminiClientAdapter.js +36 -12
  13. package/dist/llm/clients/LlamaCppClientAdapter.js +43 -23
  14. package/dist/llm/clients/MistralClientAdapter.d.ts +94 -0
  15. package/dist/llm/clients/MistralClientAdapter.js +239 -0
  16. package/dist/llm/clients/OpenAIClientAdapter.js +36 -17
  17. package/dist/llm/clients/OpenRouterClientAdapter.d.ts +103 -0
  18. package/dist/llm/clients/OpenRouterClientAdapter.js +285 -0
  19. package/dist/llm/config.js +75 -32
  20. package/dist/llm/services/ModelResolver.d.ts +3 -1
  21. package/dist/llm/services/ModelResolver.js +5 -3
  22. package/dist/llm/services/SettingsManager.d.ts +3 -0
  23. package/dist/llm/services/SettingsManager.js +29 -20
  24. package/dist/llm/types.d.ts +79 -0
  25. package/dist/logging/defaultLogger.d.ts +35 -0
  26. package/dist/logging/defaultLogger.js +94 -0
  27. package/dist/logging/index.d.ts +2 -0
  28. package/dist/logging/index.js +7 -0
  29. package/dist/logging/types.d.ts +23 -0
  30. package/dist/logging/types.js +2 -0
  31. package/dist/prompting/parser.js +4 -1
  32. package/dist/shared/adapters/systemMessageUtils.d.ts +162 -0
  33. package/dist/shared/adapters/systemMessageUtils.js +172 -0
  34. package/dist/shared/services/AdapterRegistry.d.ts +4 -1
  35. package/dist/shared/services/AdapterRegistry.js +12 -9
  36. package/dist/types/image.d.ts +5 -0
  37. package/package.json +2 -1
  38. package/src/config/llm-presets.json +40 -44
@@ -0,0 +1,172 @@
1
+ "use strict";
2
+ // AI Summary: Shared utilities for handling system messages across LLM adapters.
3
+ // Provides functions to collect, combine, and transform system content for models
4
+ // that don't support native system instructions.
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DEFAULT_SYSTEM_MESSAGE_FORMAT_OPTIONS = void 0;
7
+ exports.formatSystemContentForPrepend = formatSystemContentForPrepend;
8
+ exports.collectSystemContent = collectSystemContent;
9
+ exports.prependSystemToFirstUserMessage = prependSystemToFirstUserMessage;
10
+ exports.processMessagesForSystemSupport = processMessagesForSystemSupport;
11
+ /**
12
+ * Default format options for system message fallback
13
+ */
14
+ exports.DEFAULT_SYSTEM_MESSAGE_FORMAT_OPTIONS = {
15
+ format: 'xml',
16
+ tagName: 'system',
17
+ separator: '\n\n---\n\n',
18
+ };
19
+ /**
20
+ * Formats system content according to the specified format options.
21
+ *
22
+ * @param systemContent - The system content to format
23
+ * @param userContent - The original user message content
24
+ * @param options - Format options (defaults to XML with 'system' tag)
25
+ * @returns The formatted combined content
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * // XML format (default)
30
+ * formatSystemContentForPrepend('Be helpful', 'Hello', { format: 'xml' });
31
+ * // Returns: '<system>\nBe helpful\n</system>\n\nHello'
32
+ *
33
+ * // Separator format (default separator is '\n\n---\n\n')
34
+ * formatSystemContentForPrepend('Be helpful', 'Hello', { format: 'separator' });
35
+ * // Returns: 'Be helpful\n\n---\n\nHello'
36
+ *
37
+ * // Custom separator (specify full separator including whitespace)
38
+ * formatSystemContentForPrepend('Be helpful', 'Hello', { format: 'separator', separator: '\n\n===\n\n' });
39
+ * // Returns: 'Be helpful\n\n===\n\nHello'
40
+ *
41
+ * // Plain format
42
+ * formatSystemContentForPrepend('Be helpful', 'Hello', { format: 'plain' });
43
+ * // Returns: 'Be helpful\n\nHello'
44
+ * ```
45
+ */
46
+ function formatSystemContentForPrepend(systemContent, userContent, options) {
47
+ const opts = { ...exports.DEFAULT_SYSTEM_MESSAGE_FORMAT_OPTIONS, ...options };
48
+ switch (opts.format) {
49
+ case 'xml':
50
+ return `<${opts.tagName}>\n${systemContent}\n</${opts.tagName}>\n\n${userContent}`;
51
+ case 'separator':
52
+ return `${systemContent}${opts.separator}${userContent}`;
53
+ case 'plain':
54
+ default:
55
+ return `${systemContent}\n\n${userContent}`;
56
+ }
57
+ }
58
+ /**
59
+ * Collects and combines system content from multiple sources.
60
+ *
61
+ * Combines the request-level systemMessage with any inline system messages
62
+ * from the messages array into a single string.
63
+ *
64
+ * @param requestSystemMessage - The request.systemMessage field (if any)
65
+ * @param inlineSystemMessages - Array of system message contents from the messages array
66
+ * @param supportsSystemMessage - Whether the model supports native system messages
67
+ * @returns Object with combined content and whether to use native support
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * const { combinedSystemContent, useNativeSystemMessage } = collectSystemContent(
72
+ * 'You are helpful',
73
+ * ['Be concise'],
74
+ * false // Model doesn't support system messages
75
+ * );
76
+ * // combinedSystemContent = 'You are helpful\n\nBe concise'
77
+ * // useNativeSystemMessage = false
78
+ * ```
79
+ */
80
+ function collectSystemContent(requestSystemMessage, inlineSystemMessages, supportsSystemMessage) {
81
+ // Combine all system content
82
+ const allSystemContent = [];
83
+ if (requestSystemMessage) {
84
+ allSystemContent.push(requestSystemMessage);
85
+ }
86
+ allSystemContent.push(...inlineSystemMessages);
87
+ const combinedSystemContent = allSystemContent.length > 0 ? allSystemContent.join("\n\n") : undefined;
88
+ return {
89
+ combinedSystemContent,
90
+ useNativeSystemMessage: supportsSystemMessage,
91
+ };
92
+ }
93
+ /**
94
+ * Prepends system content to the first user message in an array.
95
+ *
96
+ * This is used as a fallback for models that don't support native system
97
+ * instructions. The system content is formatted according to the options
98
+ * and prepended to the first user message.
99
+ *
100
+ * @param messages - Array of message objects with role and content
101
+ * @param systemContent - System content to prepend
102
+ * @param options - Format options (defaults to XML with 'system' tag)
103
+ * @returns The index of the modified message, or -1 if no user message found
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * const messages = [
108
+ * { role: 'user', content: 'Hello' },
109
+ * { role: 'assistant', content: 'Hi!' }
110
+ * ];
111
+ *
112
+ * // Default (XML format)
113
+ * prependSystemToFirstUserMessage(messages, 'Be helpful');
114
+ * // messages[0].content = '<system>\nBe helpful\n</system>\n\nHello'
115
+ *
116
+ * // Plain format
117
+ * prependSystemToFirstUserMessage(messages, 'Be helpful', { format: 'plain' });
118
+ * // messages[0].content = 'Be helpful\n\nHello'
119
+ *
120
+ * // Separator format (default separator is '\n\n---\n\n')
121
+ * prependSystemToFirstUserMessage(messages, 'Be helpful', { format: 'separator' });
122
+ * // messages[0].content = 'Be helpful\n\n---\n\nHello'
123
+ * ```
124
+ */
125
+ function prependSystemToFirstUserMessage(messages, systemContent, options) {
126
+ const firstUserIndex = messages.findIndex((m) => m.role === "user");
127
+ if (firstUserIndex !== -1) {
128
+ messages[firstUserIndex].content = formatSystemContentForPrepend(systemContent, messages[firstUserIndex].content, options);
129
+ return firstUserIndex;
130
+ }
131
+ return -1;
132
+ }
133
+ /**
134
+ * Filters system messages from an array and returns non-system messages
135
+ * along with collected system content.
136
+ *
137
+ * This is a convenience function that combines message filtering with
138
+ * system content collection in a single pass.
139
+ *
140
+ * @param messages - Array of messages to process
141
+ * @param requestSystemMessage - Optional request-level system message
142
+ * @param supportsSystemMessage - Whether the model supports native system messages
143
+ * @returns Object with filtered messages and system content handling info
144
+ *
145
+ * @example
146
+ * ```typescript
147
+ * const messages = [
148
+ * { role: 'system', content: 'Be helpful' },
149
+ * { role: 'user', content: 'Hello' }
150
+ * ];
151
+ * const result = processMessagesForSystemSupport(messages, undefined, false);
152
+ * // result.nonSystemMessages = [{ role: 'user', content: 'Hello' }]
153
+ * // result.systemContent.combinedSystemContent = 'Be helpful'
154
+ * ```
155
+ */
156
+ function processMessagesForSystemSupport(messages, requestSystemMessage, supportsSystemMessage) {
157
+ const nonSystemMessages = [];
158
+ const inlineSystemMessages = [];
159
+ for (const message of messages) {
160
+ if (message.role === "system") {
161
+ inlineSystemMessages.push(message.content);
162
+ }
163
+ else {
164
+ nonSystemMessages.push(message);
165
+ }
166
+ }
167
+ const systemContent = collectSystemContent(requestSystemMessage, inlineSystemMessages, supportsSystemMessage);
168
+ return {
169
+ nonSystemMessages,
170
+ systemContent,
171
+ };
172
+ }
@@ -1,3 +1,4 @@
1
+ import type { Logger } from "../../logging/types";
1
2
  /**
2
3
  * Information about a registered adapter
3
4
  */
@@ -50,12 +51,14 @@ export declare class AdapterRegistry<TAdapter, TProviderId extends string> {
50
51
  private adapters;
51
52
  private fallbackAdapter;
52
53
  private supportedProviders;
54
+ private logger;
53
55
  /**
54
56
  * Creates a new AdapterRegistry
55
57
  *
56
58
  * @param config - Configuration for the registry
59
+ * @param logger - Optional logger instance
57
60
  */
58
- constructor(config: AdapterRegistryConfig<TAdapter, TProviderId>);
61
+ constructor(config: AdapterRegistryConfig<TAdapter, TProviderId>, logger?: Logger);
59
62
  /**
60
63
  * Initializes adapters for all supported providers using constructors
61
64
  */
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AdapterRegistry = void 0;
4
+ const defaultLogger_1 = require("../../logging/defaultLogger");
4
5
  /**
5
6
  * Generic registry for managing service adapters across different providers.
6
7
  * Handles adapter initialization, registration, and retrieval.
@@ -13,11 +14,13 @@ class AdapterRegistry {
13
14
  * Creates a new AdapterRegistry
14
15
  *
15
16
  * @param config - Configuration for the registry
17
+ * @param logger - Optional logger instance
16
18
  */
17
- constructor(config) {
19
+ constructor(config, logger) {
18
20
  this.adapters = new Map();
19
21
  this.fallbackAdapter = config.fallbackAdapter;
20
22
  this.supportedProviders = config.supportedProviders;
23
+ this.logger = logger ?? (0, defaultLogger_1.createDefaultLogger)();
21
24
  // Register custom adapters first if provided
22
25
  if (config.customAdapters) {
23
26
  for (const [providerId, adapter] of Object.entries(config.customAdapters)) {
@@ -39,7 +42,7 @@ class AdapterRegistry {
39
42
  const providerId = provider.id;
40
43
  // Skip if adapter is already registered (from custom adapters)
41
44
  if (this.adapters.has(providerId)) {
42
- console.log(`AdapterRegistry: Skipping constructor initialization for '${provider.id}' ` +
45
+ this.logger.debug(`AdapterRegistry: Skipping constructor initialization for '${provider.id}' ` +
43
46
  `(custom adapter already registered)`);
44
47
  continue;
45
48
  }
@@ -53,21 +56,21 @@ class AdapterRegistry {
53
56
  successfullyRegisteredProviders.push(provider.id);
54
57
  }
55
58
  catch (error) {
56
- console.error(`AdapterRegistry: Failed to instantiate adapter for provider '${provider.id}'. ` +
59
+ this.logger.error(`AdapterRegistry: Failed to instantiate adapter for provider '${provider.id}'. ` +
57
60
  `This provider will use the fallback adapter. Error:`, error);
58
61
  }
59
62
  }
60
63
  else {
61
- console.warn(`AdapterRegistry: No adapter constructor found for supported provider '${provider.id}'. ` +
64
+ this.logger.warn(`AdapterRegistry: No adapter constructor found for supported provider '${provider.id}'. ` +
62
65
  `This provider will use the fallback adapter.`);
63
66
  }
64
67
  }
65
68
  if (registeredCount > 0) {
66
- console.log(`AdapterRegistry: Initialized with ${registeredCount} dynamically registered adapter(s) ` +
69
+ this.logger.debug(`AdapterRegistry: Initialized with ${registeredCount} dynamically registered adapter(s) ` +
67
70
  `for: ${successfullyRegisteredProviders.join(', ')}.`);
68
71
  }
69
72
  else {
70
- console.log(`AdapterRegistry: No real adapters were dynamically registered. ` +
73
+ this.logger.debug(`AdapterRegistry: No real adapters were dynamically registered. ` +
71
74
  `All providers will use the fallback adapter.`);
72
75
  }
73
76
  }
@@ -79,7 +82,7 @@ class AdapterRegistry {
79
82
  */
80
83
  registerAdapter(providerId, adapter) {
81
84
  this.adapters.set(providerId, adapter);
82
- console.log(`AdapterRegistry: Registered adapter for provider: ${providerId}`);
85
+ this.logger.debug(`AdapterRegistry: Registered adapter for provider: ${providerId}`);
83
86
  }
84
87
  /**
85
88
  * Gets the appropriate adapter for a provider
@@ -91,11 +94,11 @@ class AdapterRegistry {
91
94
  // Check for registered real adapters first
92
95
  const registeredAdapter = this.adapters.get(providerId);
93
96
  if (registeredAdapter) {
94
- console.log(`AdapterRegistry: Using registered adapter for provider: ${providerId}`);
97
+ this.logger.debug(`AdapterRegistry: Using registered adapter for provider: ${providerId}`);
95
98
  return registeredAdapter;
96
99
  }
97
100
  // Fall back to fallback adapter for unsupported providers
98
- console.log(`AdapterRegistry: No real adapter found for ${providerId}, using fallback adapter`);
101
+ this.logger.debug(`AdapterRegistry: No real adapter found for ${providerId}, using fallback adapter`);
99
102
  return this.fallbackAdapter;
100
103
  }
101
104
  /**
@@ -4,6 +4,7 @@
4
4
  * This module contains all types for the ImageService and image generation adapters.
5
5
  * Based on the design specification in docs/devlog/2025-10-22-genai-lite-image-api-design.md
6
6
  */
7
+ import type { Logger, LogLevel } from '../logging/types';
7
8
  /**
8
9
  * Image provider ID type - represents a unique identifier for an image generation provider
9
10
  */
@@ -387,6 +388,10 @@ export interface ImageServiceOptions {
387
388
  adapters?: Record<ImageProviderId, ImageProviderAdapter>;
388
389
  /** Override default base URLs per provider */
389
390
  baseUrls?: Record<ImageProviderId, string>;
391
+ /** Log level for filtering messages. Defaults to GENAI_LITE_LOG_LEVEL env var or 'warn'. */
392
+ logLevel?: LogLevel;
393
+ /** Custom logger implementation. If provided, logLevel is ignored. */
394
+ logger?: Logger;
390
395
  }
391
396
  /**
392
397
  * Result from createPrompt utility
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genai-lite",
3
- "version": "0.6.1",
3
+ "version": "0.7.2",
4
4
  "description": "A lightweight, portable toolkit for interacting with various Generative AI APIs.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -45,6 +45,7 @@
45
45
  "dependencies": {
46
46
  "@anthropic-ai/sdk": "^0.56.0",
47
47
  "@google/genai": "^1.0.1",
48
+ "@mistralai/mistralai": "^1.11.0",
48
49
  "js-tiktoken": "^1.0.20",
49
50
  "openai": "^5.8.2"
50
51
  },
@@ -370,50 +370,6 @@
370
370
  }
371
371
  }
372
372
  },
373
- {
374
- "id": "google-gemini-2.0-flash-default",
375
- "displayName": "Google - Gemini 2.0 Flash",
376
- "description": "Default preset for Gemini 2.0 Flash.",
377
- "providerId": "gemini",
378
- "modelId": "gemini-2.0-flash",
379
- "settings": {
380
- "temperature": 0.7,
381
- "geminiSafetySettings": [
382
- { "category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_NONE" },
383
- {
384
- "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
385
- "threshold": "BLOCK_NONE"
386
- },
387
- {
388
- "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
389
- "threshold": "BLOCK_NONE"
390
- },
391
- { "category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_NONE" }
392
- ]
393
- }
394
- },
395
- {
396
- "id": "google-gemini-2.0-flash-lite-default",
397
- "displayName": "Google - Gemini 2.0 Flash Lite",
398
- "description": "Default preset for Gemini 2.0 Flash Lite.",
399
- "providerId": "gemini",
400
- "modelId": "gemini-2.0-flash-lite",
401
- "settings": {
402
- "temperature": 0.7,
403
- "geminiSafetySettings": [
404
- { "category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_NONE" },
405
- {
406
- "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
407
- "threshold": "BLOCK_NONE"
408
- },
409
- {
410
- "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
411
- "threshold": "BLOCK_NONE"
412
- },
413
- { "category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_NONE" }
414
- ]
415
- }
416
- },
417
373
  {
418
374
  "id": "google-gemma-3-27b-default",
419
375
  "displayName": "Google - Gemma 3 27B (Free)",
@@ -599,5 +555,45 @@
599
555
  "settings": {
600
556
  "temperature": 0.7
601
557
  }
558
+ },
559
+ {
560
+ "id": "openrouter-gemma-3-27b-free",
561
+ "displayName": "OpenRouter - Gemma 3 27B (Free)",
562
+ "description": "Google's Gemma 3 27B via OpenRouter free tier.",
563
+ "providerId": "openrouter",
564
+ "modelId": "google/gemma-3-27b-it:free",
565
+ "settings": {
566
+ "temperature": 0.7
567
+ }
568
+ },
569
+ {
570
+ "id": "openrouter-mistral-small-3.1-free",
571
+ "displayName": "OpenRouter - Mistral Small 3.1 (Free)",
572
+ "description": "Mistral Small 3.1 24B via OpenRouter free tier.",
573
+ "providerId": "openrouter",
574
+ "modelId": "mistralai/mistral-small-3.1-24b-instruct:free",
575
+ "settings": {
576
+ "temperature": 0.7
577
+ }
578
+ },
579
+ {
580
+ "id": "mistral-small-default",
581
+ "displayName": "Mistral - Small",
582
+ "description": "Cost-effective Mistral Small model for general tasks.",
583
+ "providerId": "mistral",
584
+ "modelId": "mistral-small-latest",
585
+ "settings": {
586
+ "temperature": 0.7
587
+ }
588
+ },
589
+ {
590
+ "id": "mistral-codestral-default",
591
+ "displayName": "Mistral - Codestral",
592
+ "description": "Specialized model for code generation with lower temperature.",
593
+ "providerId": "mistral",
594
+ "modelId": "codestral-2501",
595
+ "settings": {
596
+ "temperature": 0.3
597
+ }
602
598
  }
603
599
  ]