genai-lite 0.6.0 → 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.
@@ -11,6 +11,8 @@ const types_1 = require("./types");
11
11
  const errorUtils_1 = require("../../shared/adapters/errorUtils");
12
12
  const LlamaCppServerClient_1 = require("./LlamaCppServerClient");
13
13
  const config_1 = require("../config");
14
+ const defaultLogger_1 = require("../../logging/defaultLogger");
15
+ const logger = (0, defaultLogger_1.createDefaultLogger)();
14
16
  /**
15
17
  * Client adapter for llama.cpp server integration
16
18
  *
@@ -78,10 +80,10 @@ class LlamaCppClientAdapter {
78
80
  }
79
81
  // Attempt detection
80
82
  try {
81
- console.log(`Detecting model capabilities from llama.cpp server at ${this.baseURL}`);
83
+ logger.debug(`Detecting model capabilities from llama.cpp server at ${this.baseURL}`);
82
84
  const { data } = await this.serverClient.getModels();
83
85
  if (!data || data.length === 0) {
84
- console.warn('No models loaded in llama.cpp server');
86
+ logger.warn('No models loaded in llama.cpp server');
85
87
  this.detectionAttempted = true;
86
88
  return null;
87
89
  }
@@ -91,15 +93,15 @@ class LlamaCppClientAdapter {
91
93
  this.cachedModelCapabilities = capabilities;
92
94
  this.detectionAttempted = true;
93
95
  if (capabilities) {
94
- console.log(`Cached model capabilities for: ${ggufFilename}`);
96
+ logger.debug(`Cached model capabilities for: ${ggufFilename}`);
95
97
  }
96
98
  else {
97
- console.log(`No known pattern matched for: ${ggufFilename}`);
99
+ logger.debug(`No known pattern matched for: ${ggufFilename}`);
98
100
  }
99
101
  return capabilities;
100
102
  }
101
103
  catch (error) {
102
- console.warn('Failed to detect model capabilities:', error);
104
+ logger.warn('Failed to detect model capabilities:', error);
103
105
  this.detectionAttempted = true;
104
106
  return null;
105
107
  }
@@ -113,7 +115,7 @@ class LlamaCppClientAdapter {
113
115
  clearModelCache() {
114
116
  this.cachedModelCapabilities = null;
115
117
  this.detectionAttempted = false;
116
- console.log('Cleared model capabilities cache');
118
+ logger.debug('Cleared model capabilities cache');
117
119
  }
118
120
  /**
119
121
  * Sends a chat message to llama.cpp server
@@ -142,7 +144,7 @@ class LlamaCppClientAdapter {
142
144
  }
143
145
  }
144
146
  catch (healthError) {
145
- console.warn('Health check failed, proceeding with request anyway:', healthError);
147
+ logger.warn('Health check failed, proceeding with request anyway:', healthError);
146
148
  }
147
149
  }
148
150
  // Initialize OpenAI client with llama.cpp base URL
@@ -170,19 +172,19 @@ class LlamaCppClientAdapter {
170
172
  presence_penalty: request.settings.presencePenalty,
171
173
  }),
172
174
  };
173
- console.log(`llama.cpp API parameters:`, {
175
+ logger.debug(`llama.cpp API parameters:`, {
174
176
  baseURL: this.baseURL,
175
177
  model: completionParams.model,
176
178
  temperature: completionParams.temperature,
177
179
  max_tokens: completionParams.max_tokens,
178
180
  top_p: completionParams.top_p,
179
181
  });
180
- console.log(`Making llama.cpp API call for model: ${request.modelId}`);
182
+ logger.info(`Making llama.cpp API call for model: ${request.modelId}`);
181
183
  // Make the API call
182
184
  const completion = await openai.chat.completions.create(completionParams);
183
185
  // Type guard to ensure we have a non-streaming response
184
186
  if ('id' in completion && 'choices' in completion) {
185
- console.log(`llama.cpp API call successful, response ID: ${completion.id}`);
187
+ logger.info(`llama.cpp API call successful, response ID: ${completion.id}`);
186
188
  return this.createSuccessResponse(completion, request);
187
189
  }
188
190
  else {
@@ -190,7 +192,7 @@ class LlamaCppClientAdapter {
190
192
  }
191
193
  }
192
194
  catch (error) {
193
- console.error("llama.cpp API error:", error);
195
+ logger.error("llama.cpp API error:", error);
194
196
  // Clear cache on connection errors so we re-detect on next request
195
197
  const errorMessage = error?.message || String(error);
196
198
  if (errorMessage.includes("ECONNREFUSED") ||
@@ -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
- console.log(`OpenAI API parameters:`, {
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
- console.log(`Making OpenAI API call for model: ${request.modelId}`);
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
- console.log(`OpenAI API call successful, response ID: ${completion.id}`);
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
- console.error("OpenAI API error:", error);
105
+ logger.error("OpenAI API error:", error);
104
106
  return this.createErrorResponse(error, request);
105
107
  }
106
108
  }
@@ -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
- console.log(`Detected GGUF model: ${model.name} (pattern: ${model.pattern})`);
276
+ logger.debug(`Detected GGUF model: ${model.name} (pattern: ${model.pattern})`);
275
277
  return model.capabilities;
276
278
  }
277
279
  }
@@ -564,8 +566,8 @@ exports.SUPPORTED_MODELS = [
564
566
  },
565
567
  },
566
568
  {
567
- id: "gemini-2.5-flash-lite-preview-06-17",
568
- name: "Gemini 2.5 Flash-Lite Preview",
569
+ id: "gemini-2.5-flash-lite",
570
+ name: "Gemini 2.5 Flash-Lite",
569
571
  providerId: "gemini",
570
572
  contextWindow: 1000000,
571
573
  inputPrice: 0.1,
@@ -588,28 +590,15 @@ exports.SUPPORTED_MODELS = [
588
590
  outputType: 'summary',
589
591
  },
590
592
  },
593
+ // Google Gemma 3 Models (Open weights, free via Gemini API)
591
594
  {
592
- id: "gemini-2.0-flash",
593
- name: "Gemini 2.0 Flash",
595
+ id: "gemma-3-27b-it",
596
+ name: "Gemma 3 27B",
594
597
  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",
598
+ contextWindow: 131072,
599
+ inputPrice: 0.0,
600
+ outputPrice: 0.0,
601
+ description: "Google's largest open model with multimodal capabilities and 128K context (free via Gemini API)",
613
602
  maxTokens: 8192,
614
603
  supportsImages: true,
615
604
  supportsPromptCache: false,
@@ -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
- constructor(presetManager: PresetManager<ModelPreset>, adapterRegistry: AdapterRegistry<ILLMClientAdapter, ApiProviderId>);
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
- console.warn('Failed to detect GGUF model capabilities:', error);
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
- console.warn(`⚠️ Unknown model "${options.modelId}" for provider "${options.providerId}". ` +
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
- console.log(`Merged settings for ${providerId}/${modelId}:`, {
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
- console.log(`LLMService: Potential parameters to exclude for provider '${providerInfo.id}', model '${modelInfo.id}':`, Array.from(paramsToExclude));
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
- console.log(`LLMService: Removing excluded parameter '${String(param)}' for provider '${providerInfo.id}', model '${modelInfo.id}'. Value was:`, filteredSettings[param]);
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
- console.log(`LLMService: Parameter '${String(param)}' marked for exclusion was not found in settings for provider '${providerInfo.id}', model '${modelInfo.id}'.`);
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
- console.log(`LLMService: Removing reasoning settings for non-reasoning model ${modelInfo.id}`);
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
- console.warn(`Unknown setting "${key}" in template metadata. Ignoring.`);
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
- console.warn(`Invalid temperature value in template: ${value}. Must be a number between 0 and 2.`);
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
- console.warn(`Invalid maxTokens value in template: ${value}. Must be a positive number.`);
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
- console.warn(`Invalid topP value in template: ${value}. Must be a number between 0 and 1.`);
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
- console.warn(`Invalid stopSequences value in template. Must be an array of strings.`);
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
- console.warn(`Invalid ${key} value in template: ${value}. Must be a number between -2 and 2.`);
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
- console.warn(`Invalid user value in template. Must be a string.`);
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
- console.warn(`Invalid supportsSystemMessage value in template. Must be a boolean.`);
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
- console.warn(`Invalid reasoning.enabled value in template. Must be a boolean.`);
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
- console.warn(`Invalid reasoning.effort value in template: ${value.effort}. Must be 'low', 'medium', or 'high'.`);
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
- console.warn(`Invalid reasoning.maxTokens value in template. Must be a positive number.`);
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
- console.warn(`Invalid reasoning.exclude value in template. Must be a boolean.`);
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
- console.warn(`Invalid thinkingTagFallback.enabled value in template. Must be a boolean.`);
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
- console.warn(`Invalid thinkingTagFallback.tagName value in template. Must be a string.`);
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
- console.warn(`Invalid thinkingTagFallback.enforce value in template. Must be a boolean.`);
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,2 @@
1
+ export type { Logger, LogLevel, LoggingConfig } from './types';
2
+ export { createDefaultLogger, DEFAULT_LOG_LEVEL, silentLogger, } from './defaultLogger';
@@ -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
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -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
- console.warn('Could not parse <META> block in template. Treating it as content.', error);
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
  */