genai-lite 0.6.1 → 0.7.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 +21 -0
- package/dist/adapters/image/GenaiElectronImageAdapter.js +6 -4
- package/dist/adapters/image/OpenAIImageAdapter.js +5 -3
- package/dist/config/llm-presets.json +0 -44
- package/dist/image/ImageService.d.ts +1 -0
- package/dist/image/ImageService.js +13 -10
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -1
- package/dist/llm/LLMService.d.ts +6 -0
- package/dist/llm/LLMService.js +20 -17
- package/dist/llm/clients/AnthropicClientAdapter.js +8 -6
- package/dist/llm/clients/GeminiClientAdapter.js +6 -4
- package/dist/llm/clients/LlamaCppClientAdapter.js +13 -11
- package/dist/llm/clients/OpenAIClientAdapter.js +6 -4
- package/dist/llm/config.js +3 -27
- package/dist/llm/services/ModelResolver.d.ts +3 -1
- package/dist/llm/services/ModelResolver.js +5 -3
- package/dist/llm/services/SettingsManager.d.ts +3 -0
- package/dist/llm/services/SettingsManager.js +24 -20
- package/dist/logging/defaultLogger.d.ts +35 -0
- package/dist/logging/defaultLogger.js +94 -0
- package/dist/logging/index.d.ts +2 -0
- package/dist/logging/index.js +7 -0
- package/dist/logging/types.d.ts +23 -0
- package/dist/logging/types.js +2 -0
- package/dist/prompting/parser.js +4 -1
- package/dist/shared/services/AdapterRegistry.d.ts +4 -1
- package/dist/shared/services/AdapterRegistry.js +12 -9
- package/dist/types/image.d.ts +5 -0
- package/package.json +1 -1
- package/src/config/llm-presets.json +0 -44
|
@@ -9,6 +9,8 @@ exports.OpenAIClientAdapter = void 0;
|
|
|
9
9
|
const openai_1 = __importDefault(require("openai"));
|
|
10
10
|
const types_1 = require("./types");
|
|
11
11
|
const errorUtils_1 = require("../../shared/adapters/errorUtils");
|
|
12
|
+
const defaultLogger_1 = require("../../logging/defaultLogger");
|
|
13
|
+
const logger = (0, defaultLogger_1.createDefaultLogger)();
|
|
12
14
|
/**
|
|
13
15
|
* Client adapter for OpenAI API integration
|
|
14
16
|
*
|
|
@@ -76,7 +78,7 @@ class OpenAIClientAdapter {
|
|
|
76
78
|
completionParams.reasoning_effort = 'medium';
|
|
77
79
|
}
|
|
78
80
|
}
|
|
79
|
-
|
|
81
|
+
logger.debug(`OpenAI API parameters:`, {
|
|
80
82
|
model: completionParams.model,
|
|
81
83
|
temperature: completionParams.temperature,
|
|
82
84
|
max_completion_tokens: completionParams.max_completion_tokens,
|
|
@@ -86,12 +88,12 @@ class OpenAIClientAdapter {
|
|
|
86
88
|
presence_penalty: completionParams.presence_penalty,
|
|
87
89
|
hasUser: !!completionParams.user,
|
|
88
90
|
});
|
|
89
|
-
|
|
91
|
+
logger.info(`Making OpenAI API call for model: ${request.modelId}`);
|
|
90
92
|
// Make the API call
|
|
91
93
|
const completion = await openai.chat.completions.create(completionParams);
|
|
92
94
|
// Type guard to ensure we have a non-streaming response
|
|
93
95
|
if ('id' in completion && 'choices' in completion) {
|
|
94
|
-
|
|
96
|
+
logger.info(`OpenAI API call successful, response ID: ${completion.id}`);
|
|
95
97
|
// Convert to standardized response format
|
|
96
98
|
return this.createSuccessResponse(completion, request);
|
|
97
99
|
}
|
|
@@ -100,7 +102,7 @@ class OpenAIClientAdapter {
|
|
|
100
102
|
}
|
|
101
103
|
}
|
|
102
104
|
catch (error) {
|
|
103
|
-
|
|
105
|
+
logger.error("OpenAI API error:", error);
|
|
104
106
|
return this.createErrorResponse(error, request);
|
|
105
107
|
}
|
|
106
108
|
}
|
package/dist/llm/config.js
CHANGED
|
@@ -16,6 +16,8 @@ const OpenAIClientAdapter_1 = require("./clients/OpenAIClientAdapter");
|
|
|
16
16
|
const AnthropicClientAdapter_1 = require("./clients/AnthropicClientAdapter");
|
|
17
17
|
const GeminiClientAdapter_1 = require("./clients/GeminiClientAdapter");
|
|
18
18
|
const LlamaCppClientAdapter_1 = require("./clients/LlamaCppClientAdapter");
|
|
19
|
+
const defaultLogger_1 = require("../logging/defaultLogger");
|
|
20
|
+
const logger = (0, defaultLogger_1.createDefaultLogger)();
|
|
19
21
|
// Placeholder for future imports:
|
|
20
22
|
// import { MistralClientAdapter } from './clients/MistralClientAdapter';
|
|
21
23
|
/**
|
|
@@ -271,7 +273,7 @@ function detectGgufCapabilities(ggufFilename) {
|
|
|
271
273
|
// First match wins (array is pre-ordered from specific to generic)
|
|
272
274
|
for (const model of exports.KNOWN_GGUF_MODELS) {
|
|
273
275
|
if (lowerFilename.includes(model.pattern.toLowerCase())) {
|
|
274
|
-
|
|
276
|
+
logger.debug(`Detected GGUF model: ${model.name} (pattern: ${model.pattern})`);
|
|
275
277
|
return model.capabilities;
|
|
276
278
|
}
|
|
277
279
|
}
|
|
@@ -588,32 +590,6 @@ exports.SUPPORTED_MODELS = [
|
|
|
588
590
|
outputType: 'summary',
|
|
589
591
|
},
|
|
590
592
|
},
|
|
591
|
-
{
|
|
592
|
-
id: "gemini-2.0-flash",
|
|
593
|
-
name: "Gemini 2.0 Flash",
|
|
594
|
-
providerId: "gemini",
|
|
595
|
-
contextWindow: 1048576,
|
|
596
|
-
inputPrice: 0.1,
|
|
597
|
-
outputPrice: 0.4,
|
|
598
|
-
description: "High-performance model with multimodal capabilities",
|
|
599
|
-
maxTokens: 8192,
|
|
600
|
-
supportsImages: true,
|
|
601
|
-
supportsPromptCache: true,
|
|
602
|
-
cacheReadsPrice: 0.025,
|
|
603
|
-
cacheWritesPrice: 1.0,
|
|
604
|
-
},
|
|
605
|
-
{
|
|
606
|
-
id: "gemini-2.0-flash-lite",
|
|
607
|
-
name: "Gemini 2.0 Flash Lite",
|
|
608
|
-
providerId: "gemini",
|
|
609
|
-
contextWindow: 1048576,
|
|
610
|
-
inputPrice: 0.075,
|
|
611
|
-
outputPrice: 0.3,
|
|
612
|
-
description: "Lightweight version of Gemini 2.0 Flash",
|
|
613
|
-
maxTokens: 8192,
|
|
614
|
-
supportsImages: true,
|
|
615
|
-
supportsPromptCache: false,
|
|
616
|
-
},
|
|
617
593
|
// Google Gemma 3 Models (Open weights, free via Gemini API)
|
|
618
594
|
{
|
|
619
595
|
id: "gemma-3-27b-it",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { LLMFailureResponse, LLMSettings, ModelInfo, ApiProviderId } from "../types";
|
|
2
2
|
import type { ILLMClientAdapter } from "../clients/types";
|
|
3
3
|
import type { ModelPreset } from "../../types/presets";
|
|
4
|
+
import type { Logger } from "../../logging/types";
|
|
4
5
|
import { PresetManager } from "../../shared/services/PresetManager";
|
|
5
6
|
import { AdapterRegistry } from "../../shared/services/AdapterRegistry";
|
|
6
7
|
/**
|
|
@@ -28,7 +29,8 @@ export interface ModelResolution {
|
|
|
28
29
|
export declare class ModelResolver {
|
|
29
30
|
private presetManager;
|
|
30
31
|
private adapterRegistry;
|
|
31
|
-
|
|
32
|
+
private logger;
|
|
33
|
+
constructor(presetManager: PresetManager<ModelPreset>, adapterRegistry: AdapterRegistry<ILLMClientAdapter, ApiProviderId>, logger?: Logger);
|
|
32
34
|
/**
|
|
33
35
|
* Resolves model information from either a preset ID or provider/model IDs
|
|
34
36
|
*
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ModelResolver = void 0;
|
|
4
|
+
const defaultLogger_1 = require("../../logging/defaultLogger");
|
|
4
5
|
const config_1 = require("../config");
|
|
5
6
|
/**
|
|
6
7
|
* Resolves model information from presets or direct provider/model IDs
|
|
7
8
|
*/
|
|
8
9
|
class ModelResolver {
|
|
9
|
-
constructor(presetManager, adapterRegistry) {
|
|
10
|
+
constructor(presetManager, adapterRegistry, logger) {
|
|
10
11
|
this.presetManager = presetManager;
|
|
11
12
|
this.adapterRegistry = adapterRegistry;
|
|
13
|
+
this.logger = logger ?? (0, defaultLogger_1.createDefaultLogger)();
|
|
12
14
|
}
|
|
13
15
|
/**
|
|
14
16
|
* Resolves model information from either a preset ID or provider/model IDs
|
|
@@ -107,7 +109,7 @@ class ModelResolver {
|
|
|
107
109
|
}
|
|
108
110
|
}
|
|
109
111
|
catch (error) {
|
|
110
|
-
|
|
112
|
+
this.logger.warn('Failed to detect GGUF model capabilities:', error);
|
|
111
113
|
// Continue with fallback
|
|
112
114
|
}
|
|
113
115
|
}
|
|
@@ -117,7 +119,7 @@ class ModelResolver {
|
|
|
117
119
|
}
|
|
118
120
|
else {
|
|
119
121
|
// Strict provider - warn but allow
|
|
120
|
-
|
|
122
|
+
this.logger.warn(`Unknown model "${options.modelId}" for provider "${options.providerId}". ` +
|
|
121
123
|
`Using default settings. This may fail at the provider API if the model doesn't exist.`);
|
|
122
124
|
modelInfo = (0, config_1.createFallbackModelInfo)(options.modelId, options.providerId, detectedCapabilities);
|
|
123
125
|
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type { ApiProviderId, LLMSettings, ModelInfo, ProviderInfo } from "../types";
|
|
2
|
+
import type { Logger } from "../../logging/types";
|
|
2
3
|
/**
|
|
3
4
|
* Manages LLM settings including merging with defaults and filtering unsupported parameters
|
|
4
5
|
*/
|
|
5
6
|
export declare class SettingsManager {
|
|
7
|
+
private logger;
|
|
8
|
+
constructor(logger?: Logger);
|
|
6
9
|
/**
|
|
7
10
|
* Merges request settings with model-specific and global defaults
|
|
8
11
|
*
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SettingsManager = void 0;
|
|
4
|
+
const defaultLogger_1 = require("../../logging/defaultLogger");
|
|
4
5
|
const config_1 = require("../config");
|
|
5
6
|
/**
|
|
6
7
|
* Manages LLM settings including merging with defaults and filtering unsupported parameters
|
|
7
8
|
*/
|
|
8
9
|
class SettingsManager {
|
|
10
|
+
constructor(logger) {
|
|
11
|
+
this.logger = logger ?? (0, defaultLogger_1.createDefaultLogger)();
|
|
12
|
+
}
|
|
9
13
|
/**
|
|
10
14
|
* Merges request settings with model-specific and global defaults
|
|
11
15
|
*
|
|
@@ -40,7 +44,7 @@ class SettingsManager {
|
|
|
40
44
|
},
|
|
41
45
|
};
|
|
42
46
|
// Log the final settings for debugging
|
|
43
|
-
|
|
47
|
+
this.logger.debug(`Merged settings for ${providerId}/${modelId}:`, {
|
|
44
48
|
temperature: mergedSettings.temperature,
|
|
45
49
|
maxTokens: mergedSettings.maxTokens,
|
|
46
50
|
topP: mergedSettings.topP,
|
|
@@ -74,23 +78,23 @@ class SettingsManager {
|
|
|
74
78
|
modelInfo.unsupportedParameters.forEach((param) => paramsToExclude.add(param));
|
|
75
79
|
}
|
|
76
80
|
if (paramsToExclude.size > 0) {
|
|
77
|
-
|
|
81
|
+
this.logger.debug(`LLMService: Potential parameters to exclude for provider '${providerInfo.id}', model '${modelInfo.id}':`, Array.from(paramsToExclude));
|
|
78
82
|
}
|
|
79
83
|
paramsToExclude.forEach((param) => {
|
|
80
84
|
// Check if the parameter key actually exists in filteredSettings before trying to delete
|
|
81
85
|
if (param in filteredSettings) {
|
|
82
|
-
|
|
86
|
+
this.logger.debug(`LLMService: Removing excluded parameter '${String(param)}' for provider '${providerInfo.id}', model '${modelInfo.id}'. Value was:`, filteredSettings[param]);
|
|
83
87
|
delete filteredSettings[param]; // Cast to allow deletion
|
|
84
88
|
}
|
|
85
89
|
else {
|
|
86
90
|
// This case should ideally not happen if settings truly is Required<LLMSettings>
|
|
87
|
-
|
|
91
|
+
this.logger.debug(`LLMService: Parameter '${String(param)}' marked for exclusion was not found in settings for provider '${providerInfo.id}', model '${modelInfo.id}'.`);
|
|
88
92
|
}
|
|
89
93
|
});
|
|
90
94
|
// Handle reasoning settings for models that don't support it
|
|
91
95
|
// This happens after validateReasoningSettings so we know it's safe to strip
|
|
92
96
|
if (!modelInfo.reasoning?.supported && filteredSettings.reasoning) {
|
|
93
|
-
|
|
97
|
+
this.logger.debug(`LLMService: Removing reasoning settings for non-reasoning model ${modelInfo.id}`);
|
|
94
98
|
delete filteredSettings.reasoning;
|
|
95
99
|
}
|
|
96
100
|
return filteredSettings;
|
|
@@ -121,71 +125,71 @@ class SettingsManager {
|
|
|
121
125
|
for (const [key, value] of Object.entries(settings)) {
|
|
122
126
|
// Check if it's a known field
|
|
123
127
|
if (!knownFields.includes(key)) {
|
|
124
|
-
|
|
128
|
+
this.logger.warn(`Unknown setting "${key}" in template metadata. Ignoring.`);
|
|
125
129
|
continue;
|
|
126
130
|
}
|
|
127
131
|
// Type-specific validation
|
|
128
132
|
if (key === 'temperature') {
|
|
129
133
|
if (typeof value !== 'number' || value < 0 || value > 2) {
|
|
130
|
-
|
|
134
|
+
this.logger.warn(`Invalid temperature value in template: ${value}. Must be a number between 0 and 2.`);
|
|
131
135
|
continue;
|
|
132
136
|
}
|
|
133
137
|
}
|
|
134
138
|
if (key === 'maxTokens') {
|
|
135
139
|
if (typeof value !== 'number' || value <= 0) {
|
|
136
|
-
|
|
140
|
+
this.logger.warn(`Invalid maxTokens value in template: ${value}. Must be a positive number.`);
|
|
137
141
|
continue;
|
|
138
142
|
}
|
|
139
143
|
}
|
|
140
144
|
if (key === 'topP') {
|
|
141
145
|
if (typeof value !== 'number' || value < 0 || value > 1) {
|
|
142
|
-
|
|
146
|
+
this.logger.warn(`Invalid topP value in template: ${value}. Must be a number between 0 and 1.`);
|
|
143
147
|
continue;
|
|
144
148
|
}
|
|
145
149
|
}
|
|
146
150
|
if (key === 'stopSequences') {
|
|
147
151
|
if (!Array.isArray(value) || !value.every(v => typeof v === 'string')) {
|
|
148
|
-
|
|
152
|
+
this.logger.warn(`Invalid stopSequences value in template. Must be an array of strings.`);
|
|
149
153
|
continue;
|
|
150
154
|
}
|
|
151
155
|
}
|
|
152
156
|
if ((key === 'frequencyPenalty' || key === 'presencePenalty')) {
|
|
153
157
|
if (typeof value !== 'number' || value < -2 || value > 2) {
|
|
154
|
-
|
|
158
|
+
this.logger.warn(`Invalid ${key} value in template: ${value}. Must be a number between -2 and 2.`);
|
|
155
159
|
continue;
|
|
156
160
|
}
|
|
157
161
|
}
|
|
158
162
|
if (key === 'user' && typeof value !== 'string') {
|
|
159
|
-
|
|
163
|
+
this.logger.warn(`Invalid user value in template. Must be a string.`);
|
|
160
164
|
continue;
|
|
161
165
|
}
|
|
162
166
|
if (key === 'supportsSystemMessage' && typeof value !== 'boolean') {
|
|
163
|
-
|
|
167
|
+
this.logger.warn(`Invalid supportsSystemMessage value in template. Must be a boolean.`);
|
|
164
168
|
continue;
|
|
165
169
|
}
|
|
166
170
|
// Nested object validation
|
|
167
171
|
if (key === 'reasoning' && typeof value === 'object' && value !== null) {
|
|
168
172
|
const reasoningValidated = {};
|
|
169
173
|
if ('enabled' in value && typeof value.enabled !== 'boolean') {
|
|
170
|
-
|
|
174
|
+
this.logger.warn(`Invalid reasoning.enabled value in template. Must be a boolean.`);
|
|
171
175
|
}
|
|
172
176
|
else if ('enabled' in value) {
|
|
173
177
|
reasoningValidated.enabled = value.enabled;
|
|
174
178
|
}
|
|
175
179
|
if ('effort' in value && !['low', 'medium', 'high'].includes(value.effort)) {
|
|
176
|
-
|
|
180
|
+
this.logger.warn(`Invalid reasoning.effort value in template: ${value.effort}. Must be 'low', 'medium', or 'high'.`);
|
|
177
181
|
}
|
|
178
182
|
else if ('effort' in value) {
|
|
179
183
|
reasoningValidated.effort = value.effort;
|
|
180
184
|
}
|
|
181
185
|
if ('maxTokens' in value && (typeof value.maxTokens !== 'number' || value.maxTokens <= 0)) {
|
|
182
|
-
|
|
186
|
+
this.logger.warn(`Invalid reasoning.maxTokens value in template. Must be a positive number.`);
|
|
183
187
|
}
|
|
184
188
|
else if ('maxTokens' in value) {
|
|
185
189
|
reasoningValidated.maxTokens = value.maxTokens;
|
|
186
190
|
}
|
|
187
191
|
if ('exclude' in value && typeof value.exclude !== 'boolean') {
|
|
188
|
-
|
|
192
|
+
this.logger.warn(`Invalid reasoning.exclude value in template. Must be a boolean.`);
|
|
189
193
|
}
|
|
190
194
|
else if ('exclude' in value) {
|
|
191
195
|
reasoningValidated.exclude = value.exclude;
|
|
@@ -198,19 +202,19 @@ class SettingsManager {
|
|
|
198
202
|
if (key === 'thinkingTagFallback' && typeof value === 'object' && value !== null) {
|
|
199
203
|
const thinkingValidated = {};
|
|
200
204
|
if ('enabled' in value && typeof value.enabled !== 'boolean') {
|
|
201
|
-
|
|
205
|
+
this.logger.warn(`Invalid thinkingTagFallback.enabled value in template. Must be a boolean.`);
|
|
202
206
|
}
|
|
203
207
|
else if ('enabled' in value) {
|
|
204
208
|
thinkingValidated.enabled = value.enabled;
|
|
205
209
|
}
|
|
206
210
|
if ('tagName' in value && typeof value.tagName !== 'string') {
|
|
207
|
-
|
|
211
|
+
this.logger.warn(`Invalid thinkingTagFallback.tagName value in template. Must be a string.`);
|
|
208
212
|
}
|
|
209
213
|
else if ('tagName' in value) {
|
|
210
214
|
thinkingValidated.tagName = value.tagName;
|
|
211
215
|
}
|
|
212
216
|
if ('enforce' in value && typeof value.enforce !== 'boolean') {
|
|
213
|
-
|
|
217
|
+
this.logger.warn(`Invalid thinkingTagFallback.enforce value in template. Must be a boolean.`);
|
|
214
218
|
}
|
|
215
219
|
else if ('enforce' in value) {
|
|
216
220
|
thinkingValidated.enforce = value.enforce;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Logger, LogLevel } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* The default log level, read once at module initialization.
|
|
4
|
+
* Can be overridden per-service via constructor options.
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_LOG_LEVEL: LogLevel;
|
|
7
|
+
/**
|
|
8
|
+
* Creates a default console-based logger with level filtering.
|
|
9
|
+
*
|
|
10
|
+
* @param level - The minimum log level to output (defaults to env var or 'warn')
|
|
11
|
+
* @returns A Logger instance that filters messages below the specified level
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const logger = createDefaultLogger('debug');
|
|
16
|
+
* logger.debug('This will be shown');
|
|
17
|
+
* logger.info('This will be shown');
|
|
18
|
+
*
|
|
19
|
+
* const quietLogger = createDefaultLogger('error');
|
|
20
|
+
* quietLogger.debug('This will be suppressed');
|
|
21
|
+
* quietLogger.info('This will be suppressed');
|
|
22
|
+
* quietLogger.error('This will be shown');
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function createDefaultLogger(level?: LogLevel): Logger;
|
|
26
|
+
/**
|
|
27
|
+
* A silent logger that discards all output.
|
|
28
|
+
* Useful for testing or when logging should be completely disabled.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const service = new LLMService(apiKeyProvider, { logger: silentLogger });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare const silentLogger: Logger;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.silentLogger = exports.DEFAULT_LOG_LEVEL = void 0;
|
|
4
|
+
exports.createDefaultLogger = createDefaultLogger;
|
|
5
|
+
/**
|
|
6
|
+
* Numeric values for log levels (higher = more verbose)
|
|
7
|
+
*/
|
|
8
|
+
const LOG_LEVEL_VALUES = {
|
|
9
|
+
silent: 0,
|
|
10
|
+
error: 1,
|
|
11
|
+
warn: 2,
|
|
12
|
+
info: 3,
|
|
13
|
+
debug: 4,
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Valid log level strings for validation
|
|
17
|
+
*/
|
|
18
|
+
const VALID_LOG_LEVELS = new Set(['silent', 'error', 'warn', 'info', 'debug']);
|
|
19
|
+
/**
|
|
20
|
+
* Reads the default log level from environment variable.
|
|
21
|
+
* Called once at module load time.
|
|
22
|
+
*
|
|
23
|
+
* @returns The log level from GENAI_LITE_LOG_LEVEL or 'warn' as default
|
|
24
|
+
*/
|
|
25
|
+
function getDefaultLogLevelFromEnv() {
|
|
26
|
+
const envLevel = process.env.GENAI_LITE_LOG_LEVEL?.toLowerCase();
|
|
27
|
+
if (envLevel && VALID_LOG_LEVELS.has(envLevel)) {
|
|
28
|
+
return envLevel;
|
|
29
|
+
}
|
|
30
|
+
return 'warn'; // Sensible default: errors + warnings
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The default log level, read once at module initialization.
|
|
34
|
+
* Can be overridden per-service via constructor options.
|
|
35
|
+
*/
|
|
36
|
+
exports.DEFAULT_LOG_LEVEL = getDefaultLogLevelFromEnv();
|
|
37
|
+
/**
|
|
38
|
+
* Creates a default console-based logger with level filtering.
|
|
39
|
+
*
|
|
40
|
+
* @param level - The minimum log level to output (defaults to env var or 'warn')
|
|
41
|
+
* @returns A Logger instance that filters messages below the specified level
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const logger = createDefaultLogger('debug');
|
|
46
|
+
* logger.debug('This will be shown');
|
|
47
|
+
* logger.info('This will be shown');
|
|
48
|
+
*
|
|
49
|
+
* const quietLogger = createDefaultLogger('error');
|
|
50
|
+
* quietLogger.debug('This will be suppressed');
|
|
51
|
+
* quietLogger.info('This will be suppressed');
|
|
52
|
+
* quietLogger.error('This will be shown');
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
function createDefaultLogger(level = exports.DEFAULT_LOG_LEVEL) {
|
|
56
|
+
const threshold = LOG_LEVEL_VALUES[level];
|
|
57
|
+
return {
|
|
58
|
+
debug(message, ...args) {
|
|
59
|
+
if (threshold >= LOG_LEVEL_VALUES.debug) {
|
|
60
|
+
console.log(`[genai-lite:debug] ${message}`, ...args);
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
info(message, ...args) {
|
|
64
|
+
if (threshold >= LOG_LEVEL_VALUES.info) {
|
|
65
|
+
console.log(`[genai-lite:info] ${message}`, ...args);
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
warn(message, ...args) {
|
|
69
|
+
if (threshold >= LOG_LEVEL_VALUES.warn) {
|
|
70
|
+
console.warn(`[genai-lite:warn] ${message}`, ...args);
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
error(message, ...args) {
|
|
74
|
+
if (threshold >= LOG_LEVEL_VALUES.error) {
|
|
75
|
+
console.error(`[genai-lite:error] ${message}`, ...args);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* A silent logger that discards all output.
|
|
82
|
+
* Useful for testing or when logging should be completely disabled.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```typescript
|
|
86
|
+
* const service = new LLMService(apiKeyProvider, { logger: silentLogger });
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
exports.silentLogger = {
|
|
90
|
+
debug: () => { },
|
|
91
|
+
info: () => { },
|
|
92
|
+
warn: () => { },
|
|
93
|
+
error: () => { },
|
|
94
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.silentLogger = exports.DEFAULT_LOG_LEVEL = exports.createDefaultLogger = void 0;
|
|
4
|
+
var defaultLogger_1 = require("./defaultLogger");
|
|
5
|
+
Object.defineProperty(exports, "createDefaultLogger", { enumerable: true, get: function () { return defaultLogger_1.createDefaultLogger; } });
|
|
6
|
+
Object.defineProperty(exports, "DEFAULT_LOG_LEVEL", { enumerable: true, get: function () { return defaultLogger_1.DEFAULT_LOG_LEVEL; } });
|
|
7
|
+
Object.defineProperty(exports, "silentLogger", { enumerable: true, get: function () { return defaultLogger_1.silentLogger; } });
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log level type - ordered from most quiet to most verbose
|
|
3
|
+
*/
|
|
4
|
+
export type LogLevel = 'silent' | 'error' | 'warn' | 'info' | 'debug';
|
|
5
|
+
/**
|
|
6
|
+
* Logger interface compatible with popular logging libraries
|
|
7
|
+
* (pino, winston, bunyan, console all have these methods)
|
|
8
|
+
*/
|
|
9
|
+
export interface Logger {
|
|
10
|
+
debug(message: string, ...args: unknown[]): void;
|
|
11
|
+
info(message: string, ...args: unknown[]): void;
|
|
12
|
+
warn(message: string, ...args: unknown[]): void;
|
|
13
|
+
error(message: string, ...args: unknown[]): void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Configuration for the logging system
|
|
17
|
+
*/
|
|
18
|
+
export interface LoggingConfig {
|
|
19
|
+
/** Log level threshold - messages below this level are suppressed */
|
|
20
|
+
level: LogLevel;
|
|
21
|
+
/** Custom logger implementation (optional) */
|
|
22
|
+
logger?: Logger;
|
|
23
|
+
}
|
package/dist/prompting/parser.js
CHANGED
|
@@ -10,6 +10,9 @@ exports.parseStructuredContent = parseStructuredContent;
|
|
|
10
10
|
exports.extractInitialTaggedContent = extractInitialTaggedContent;
|
|
11
11
|
exports.parseRoleTags = parseRoleTags;
|
|
12
12
|
exports.parseTemplateWithMetadata = parseTemplateWithMetadata;
|
|
13
|
+
const defaultLogger_1 = require("../logging/defaultLogger");
|
|
14
|
+
// Module-level logger for utility functions
|
|
15
|
+
const logger = (0, defaultLogger_1.createDefaultLogger)();
|
|
13
16
|
/**
|
|
14
17
|
* Parses a string containing structured data wrapped in custom XML-style tags.
|
|
15
18
|
*
|
|
@@ -183,7 +186,7 @@ function parseTemplateWithMetadata(template) {
|
|
|
183
186
|
catch (error) {
|
|
184
187
|
// If the JSON is invalid, we warn the developer and treat the <META> block
|
|
185
188
|
// as regular text to avoid crashing.
|
|
186
|
-
|
|
189
|
+
logger.warn('Could not parse <META> block in template. Treating it as content.', error);
|
|
187
190
|
return { metadata: { settings: {} }, content: template };
|
|
188
191
|
}
|
|
189
192
|
}
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
69
|
+
this.logger.debug(`AdapterRegistry: Initialized with ${registeredCount} dynamically registered adapter(s) ` +
|
|
67
70
|
`for: ${successfullyRegisteredProviders.join(', ')}.`);
|
|
68
71
|
}
|
|
69
72
|
else {
|
|
70
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
101
|
+
this.logger.debug(`AdapterRegistry: No real adapter found for ${providerId}, using fallback adapter`);
|
|
99
102
|
return this.fallbackAdapter;
|
|
100
103
|
}
|
|
101
104
|
/**
|
package/dist/types/image.d.ts
CHANGED
|
@@ -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
|