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.
- 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 +40 -44
- package/dist/image/ImageService.d.ts +1 -0
- package/dist/image/ImageService.js +13 -10
- package/dist/index.d.ts +6 -0
- package/dist/index.js +11 -1
- package/dist/llm/LLMService.d.ts +6 -0
- package/dist/llm/LLMService.js +20 -17
- package/dist/llm/clients/AnthropicClientAdapter.js +36 -15
- package/dist/llm/clients/GeminiClientAdapter.js +36 -12
- package/dist/llm/clients/LlamaCppClientAdapter.js +43 -23
- package/dist/llm/clients/MistralClientAdapter.d.ts +94 -0
- package/dist/llm/clients/MistralClientAdapter.js +239 -0
- package/dist/llm/clients/OpenAIClientAdapter.js +36 -17
- package/dist/llm/clients/OpenRouterClientAdapter.d.ts +103 -0
- package/dist/llm/clients/OpenRouterClientAdapter.js +285 -0
- package/dist/llm/config.js +75 -32
- 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 +29 -20
- package/dist/llm/types.d.ts +79 -0
- 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/adapters/systemMessageUtils.d.ts +162 -0
- package/dist/shared/adapters/systemMessageUtils.js +172 -0
- 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 +2 -1
- package/src/config/llm-presets.json +40 -44
|
@@ -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
|
*
|
|
@@ -28,6 +32,10 @@ class SettingsManager {
|
|
|
28
32
|
user: requestSettings?.user ?? modelDefaults.user,
|
|
29
33
|
supportsSystemMessage: requestSettings?.supportsSystemMessage ??
|
|
30
34
|
modelDefaults.supportsSystemMessage,
|
|
35
|
+
systemMessageFallback: {
|
|
36
|
+
...modelDefaults.systemMessageFallback,
|
|
37
|
+
...requestSettings?.systemMessageFallback,
|
|
38
|
+
},
|
|
31
39
|
geminiSafetySettings: requestSettings?.geminiSafetySettings ??
|
|
32
40
|
modelDefaults.geminiSafetySettings,
|
|
33
41
|
reasoning: {
|
|
@@ -38,9 +46,10 @@ class SettingsManager {
|
|
|
38
46
|
...modelDefaults.thinkingTagFallback,
|
|
39
47
|
...requestSettings?.thinkingTagFallback,
|
|
40
48
|
},
|
|
49
|
+
openRouterProvider: requestSettings?.openRouterProvider ?? modelDefaults.openRouterProvider,
|
|
41
50
|
};
|
|
42
51
|
// Log the final settings for debugging
|
|
43
|
-
|
|
52
|
+
this.logger.debug(`Merged settings for ${providerId}/${modelId}:`, {
|
|
44
53
|
temperature: mergedSettings.temperature,
|
|
45
54
|
maxTokens: mergedSettings.maxTokens,
|
|
46
55
|
topP: mergedSettings.topP,
|
|
@@ -74,23 +83,23 @@ class SettingsManager {
|
|
|
74
83
|
modelInfo.unsupportedParameters.forEach((param) => paramsToExclude.add(param));
|
|
75
84
|
}
|
|
76
85
|
if (paramsToExclude.size > 0) {
|
|
77
|
-
|
|
86
|
+
this.logger.debug(`LLMService: Potential parameters to exclude for provider '${providerInfo.id}', model '${modelInfo.id}':`, Array.from(paramsToExclude));
|
|
78
87
|
}
|
|
79
88
|
paramsToExclude.forEach((param) => {
|
|
80
89
|
// Check if the parameter key actually exists in filteredSettings before trying to delete
|
|
81
90
|
if (param in filteredSettings) {
|
|
82
|
-
|
|
91
|
+
this.logger.debug(`LLMService: Removing excluded parameter '${String(param)}' for provider '${providerInfo.id}', model '${modelInfo.id}'. Value was:`, filteredSettings[param]);
|
|
83
92
|
delete filteredSettings[param]; // Cast to allow deletion
|
|
84
93
|
}
|
|
85
94
|
else {
|
|
86
95
|
// This case should ideally not happen if settings truly is Required<LLMSettings>
|
|
87
|
-
|
|
96
|
+
this.logger.debug(`LLMService: Parameter '${String(param)}' marked for exclusion was not found in settings for provider '${providerInfo.id}', model '${modelInfo.id}'.`);
|
|
88
97
|
}
|
|
89
98
|
});
|
|
90
99
|
// Handle reasoning settings for models that don't support it
|
|
91
100
|
// This happens after validateReasoningSettings so we know it's safe to strip
|
|
92
101
|
if (!modelInfo.reasoning?.supported && filteredSettings.reasoning) {
|
|
93
|
-
|
|
102
|
+
this.logger.debug(`LLMService: Removing reasoning settings for non-reasoning model ${modelInfo.id}`);
|
|
94
103
|
delete filteredSettings.reasoning;
|
|
95
104
|
}
|
|
96
105
|
return filteredSettings;
|
|
@@ -121,71 +130,71 @@ class SettingsManager {
|
|
|
121
130
|
for (const [key, value] of Object.entries(settings)) {
|
|
122
131
|
// Check if it's a known field
|
|
123
132
|
if (!knownFields.includes(key)) {
|
|
124
|
-
|
|
133
|
+
this.logger.warn(`Unknown setting "${key}" in template metadata. Ignoring.`);
|
|
125
134
|
continue;
|
|
126
135
|
}
|
|
127
136
|
// Type-specific validation
|
|
128
137
|
if (key === 'temperature') {
|
|
129
138
|
if (typeof value !== 'number' || value < 0 || value > 2) {
|
|
130
|
-
|
|
139
|
+
this.logger.warn(`Invalid temperature value in template: ${value}. Must be a number between 0 and 2.`);
|
|
131
140
|
continue;
|
|
132
141
|
}
|
|
133
142
|
}
|
|
134
143
|
if (key === 'maxTokens') {
|
|
135
144
|
if (typeof value !== 'number' || value <= 0) {
|
|
136
|
-
|
|
145
|
+
this.logger.warn(`Invalid maxTokens value in template: ${value}. Must be a positive number.`);
|
|
137
146
|
continue;
|
|
138
147
|
}
|
|
139
148
|
}
|
|
140
149
|
if (key === 'topP') {
|
|
141
150
|
if (typeof value !== 'number' || value < 0 || value > 1) {
|
|
142
|
-
|
|
151
|
+
this.logger.warn(`Invalid topP value in template: ${value}. Must be a number between 0 and 1.`);
|
|
143
152
|
continue;
|
|
144
153
|
}
|
|
145
154
|
}
|
|
146
155
|
if (key === 'stopSequences') {
|
|
147
156
|
if (!Array.isArray(value) || !value.every(v => typeof v === 'string')) {
|
|
148
|
-
|
|
157
|
+
this.logger.warn(`Invalid stopSequences value in template. Must be an array of strings.`);
|
|
149
158
|
continue;
|
|
150
159
|
}
|
|
151
160
|
}
|
|
152
161
|
if ((key === 'frequencyPenalty' || key === 'presencePenalty')) {
|
|
153
162
|
if (typeof value !== 'number' || value < -2 || value > 2) {
|
|
154
|
-
|
|
163
|
+
this.logger.warn(`Invalid ${key} value in template: ${value}. Must be a number between -2 and 2.`);
|
|
155
164
|
continue;
|
|
156
165
|
}
|
|
157
166
|
}
|
|
158
167
|
if (key === 'user' && typeof value !== 'string') {
|
|
159
|
-
|
|
168
|
+
this.logger.warn(`Invalid user value in template. Must be a string.`);
|
|
160
169
|
continue;
|
|
161
170
|
}
|
|
162
171
|
if (key === 'supportsSystemMessage' && typeof value !== 'boolean') {
|
|
163
|
-
|
|
172
|
+
this.logger.warn(`Invalid supportsSystemMessage value in template. Must be a boolean.`);
|
|
164
173
|
continue;
|
|
165
174
|
}
|
|
166
175
|
// Nested object validation
|
|
167
176
|
if (key === 'reasoning' && typeof value === 'object' && value !== null) {
|
|
168
177
|
const reasoningValidated = {};
|
|
169
178
|
if ('enabled' in value && typeof value.enabled !== 'boolean') {
|
|
170
|
-
|
|
179
|
+
this.logger.warn(`Invalid reasoning.enabled value in template. Must be a boolean.`);
|
|
171
180
|
}
|
|
172
181
|
else if ('enabled' in value) {
|
|
173
182
|
reasoningValidated.enabled = value.enabled;
|
|
174
183
|
}
|
|
175
184
|
if ('effort' in value && !['low', 'medium', 'high'].includes(value.effort)) {
|
|
176
|
-
|
|
185
|
+
this.logger.warn(`Invalid reasoning.effort value in template: ${value.effort}. Must be 'low', 'medium', or 'high'.`);
|
|
177
186
|
}
|
|
178
187
|
else if ('effort' in value) {
|
|
179
188
|
reasoningValidated.effort = value.effort;
|
|
180
189
|
}
|
|
181
190
|
if ('maxTokens' in value && (typeof value.maxTokens !== 'number' || value.maxTokens <= 0)) {
|
|
182
|
-
|
|
191
|
+
this.logger.warn(`Invalid reasoning.maxTokens value in template. Must be a positive number.`);
|
|
183
192
|
}
|
|
184
193
|
else if ('maxTokens' in value) {
|
|
185
194
|
reasoningValidated.maxTokens = value.maxTokens;
|
|
186
195
|
}
|
|
187
196
|
if ('exclude' in value && typeof value.exclude !== 'boolean') {
|
|
188
|
-
|
|
197
|
+
this.logger.warn(`Invalid reasoning.exclude value in template. Must be a boolean.`);
|
|
189
198
|
}
|
|
190
199
|
else if ('exclude' in value) {
|
|
191
200
|
reasoningValidated.exclude = value.exclude;
|
|
@@ -198,19 +207,19 @@ class SettingsManager {
|
|
|
198
207
|
if (key === 'thinkingTagFallback' && typeof value === 'object' && value !== null) {
|
|
199
208
|
const thinkingValidated = {};
|
|
200
209
|
if ('enabled' in value && typeof value.enabled !== 'boolean') {
|
|
201
|
-
|
|
210
|
+
this.logger.warn(`Invalid thinkingTagFallback.enabled value in template. Must be a boolean.`);
|
|
202
211
|
}
|
|
203
212
|
else if ('enabled' in value) {
|
|
204
213
|
thinkingValidated.enabled = value.enabled;
|
|
205
214
|
}
|
|
206
215
|
if ('tagName' in value && typeof value.tagName !== 'string') {
|
|
207
|
-
|
|
216
|
+
this.logger.warn(`Invalid thinkingTagFallback.tagName value in template. Must be a string.`);
|
|
208
217
|
}
|
|
209
218
|
else if ('tagName' in value) {
|
|
210
219
|
thinkingValidated.tagName = value.tagName;
|
|
211
220
|
}
|
|
212
221
|
if ('enforce' in value && typeof value.enforce !== 'boolean') {
|
|
213
|
-
|
|
222
|
+
this.logger.warn(`Invalid thinkingTagFallback.enforce value in template. Must be a boolean.`);
|
|
214
223
|
}
|
|
215
224
|
else if ('enforce' in value) {
|
|
216
225
|
thinkingValidated.enforce = value.enforce;
|
package/dist/llm/types.d.ts
CHANGED
|
@@ -83,6 +83,74 @@ export interface LLMThinkingTagFallbackSettings {
|
|
|
83
83
|
*/
|
|
84
84
|
enforce?: boolean;
|
|
85
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Format options for prepending system content when model doesn't support system messages.
|
|
88
|
+
* - 'xml': Wrap in XML tags (default) - `<system>content</system>\n\n{user message}`
|
|
89
|
+
* - 'separator': Use a simple separator - `{content}\n\n---\n\n{user message}`
|
|
90
|
+
* - 'plain': Just prepend with double newline - `{content}\n\n{user message}`
|
|
91
|
+
*/
|
|
92
|
+
export type SystemMessageFallbackFormat = 'xml' | 'separator' | 'plain';
|
|
93
|
+
/**
|
|
94
|
+
* Settings for handling system messages when the model doesn't support them natively.
|
|
95
|
+
* When a model has `supportsSystemMessage: false`, these settings control how
|
|
96
|
+
* system content is formatted when prepended to the first user message.
|
|
97
|
+
*/
|
|
98
|
+
export interface SystemMessageFallbackSettings {
|
|
99
|
+
/**
|
|
100
|
+
* Format to use when prepending system content to user message.
|
|
101
|
+
* @default 'xml'
|
|
102
|
+
*/
|
|
103
|
+
format?: SystemMessageFallbackFormat;
|
|
104
|
+
/**
|
|
105
|
+
* Tag name to use when format is 'xml'.
|
|
106
|
+
* @default 'system'
|
|
107
|
+
* @example tagName: 'instructions' produces `<instructions>content</instructions>`
|
|
108
|
+
*/
|
|
109
|
+
tagName?: string;
|
|
110
|
+
/**
|
|
111
|
+
* Separator string to use when format is 'separator'.
|
|
112
|
+
* @default '---'
|
|
113
|
+
*/
|
|
114
|
+
separator?: string;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* OpenRouter-specific provider routing settings
|
|
118
|
+
*
|
|
119
|
+
* These settings allow controlling which underlying providers serve requests
|
|
120
|
+
* when using OpenRouter. All fields are optional - by default, OpenRouter
|
|
121
|
+
* automatically selects the best provider based on price, latency, and availability.
|
|
122
|
+
*
|
|
123
|
+
* @see https://openrouter.ai/docs/provider-routing
|
|
124
|
+
*/
|
|
125
|
+
export interface OpenRouterProviderSettings {
|
|
126
|
+
/**
|
|
127
|
+
* Provider priority order. OpenRouter will try providers in this order.
|
|
128
|
+
* @example order: ["Together", "Fireworks", "Lepton"]
|
|
129
|
+
*/
|
|
130
|
+
order?: string[];
|
|
131
|
+
/**
|
|
132
|
+
* Providers to exclude from serving this request.
|
|
133
|
+
* @example ignore: ["Azure", "OpenAI"]
|
|
134
|
+
*/
|
|
135
|
+
ignore?: string[];
|
|
136
|
+
/**
|
|
137
|
+
* Providers to allow exclusively. If set, only these providers can serve the request.
|
|
138
|
+
* @example allow: ["Together", "Fireworks"]
|
|
139
|
+
*/
|
|
140
|
+
allow?: string[];
|
|
141
|
+
/**
|
|
142
|
+
* Control whether providers can use your prompts for training.
|
|
143
|
+
* Set to 'deny' to opt out of data collection by providers.
|
|
144
|
+
* @default undefined (provider's default behavior)
|
|
145
|
+
*/
|
|
146
|
+
dataCollection?: 'deny' | 'allow';
|
|
147
|
+
/**
|
|
148
|
+
* If true, only route to providers that support all parameters in your request.
|
|
149
|
+
* Useful when using provider-specific features.
|
|
150
|
+
* @default false
|
|
151
|
+
*/
|
|
152
|
+
requireParameters?: boolean;
|
|
153
|
+
}
|
|
86
154
|
/**
|
|
87
155
|
* Configurable settings for LLM requests
|
|
88
156
|
*/
|
|
@@ -103,6 +171,11 @@ export interface LLMSettings {
|
|
|
103
171
|
user?: string;
|
|
104
172
|
/** Whether the LLM supports system message (almost all LLMs do nowadays) */
|
|
105
173
|
supportsSystemMessage?: boolean;
|
|
174
|
+
/**
|
|
175
|
+
* Settings for handling system messages when the model doesn't support them.
|
|
176
|
+
* Controls how system content is formatted when prepended to user messages.
|
|
177
|
+
*/
|
|
178
|
+
systemMessageFallback?: SystemMessageFallbackSettings;
|
|
106
179
|
/** Gemini-specific safety settings for content filtering */
|
|
107
180
|
geminiSafetySettings?: GeminiSafetySetting[];
|
|
108
181
|
/** Universal reasoning/thinking configuration */
|
|
@@ -121,6 +194,12 @@ export interface LLMSettings {
|
|
|
121
194
|
* The library only extracts them - it doesn't generate them automatically.
|
|
122
195
|
*/
|
|
123
196
|
thinkingTagFallback?: LLMThinkingTagFallbackSettings;
|
|
197
|
+
/**
|
|
198
|
+
* OpenRouter-specific provider routing settings.
|
|
199
|
+
* Only used when providerId is 'openrouter'.
|
|
200
|
+
* @see OpenRouterProviderSettings
|
|
201
|
+
*/
|
|
202
|
+
openRouterProvider?: OpenRouterProviderSettings;
|
|
124
203
|
}
|
|
125
204
|
/**
|
|
126
205
|
* Request structure for chat completion
|
|
@@ -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
|
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format options for prepending system content when model doesn't support system messages.
|
|
3
|
+
* - 'xml': Wrap in XML tags (default) - `<system>content</system>\n\n{user message}`
|
|
4
|
+
* - 'separator': Use a custom separator string - `{content}{separator}{user message}`
|
|
5
|
+
* Default separator is `\n\n---\n\n`. Specify full separator including whitespace.
|
|
6
|
+
* - 'plain': Just prepend with double newline - `{content}\n\n{user message}`
|
|
7
|
+
*/
|
|
8
|
+
export type SystemMessageFallbackFormat = 'xml' | 'separator' | 'plain';
|
|
9
|
+
/**
|
|
10
|
+
* Options for formatting system content when prepending to user messages
|
|
11
|
+
*/
|
|
12
|
+
export interface SystemMessageFormatOptions {
|
|
13
|
+
/**
|
|
14
|
+
* Format to use when prepending system content to user message.
|
|
15
|
+
* @default 'xml'
|
|
16
|
+
*/
|
|
17
|
+
format?: SystemMessageFallbackFormat;
|
|
18
|
+
/**
|
|
19
|
+
* Tag name to use when format is 'xml'.
|
|
20
|
+
* @default 'system'
|
|
21
|
+
* @example tagName: 'instructions' produces `<instructions>content</instructions>`
|
|
22
|
+
*/
|
|
23
|
+
tagName?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Separator string to use when format is 'separator'.
|
|
26
|
+
* Include any whitespace/newlines in the separator itself.
|
|
27
|
+
* @default '\n\n---\n\n'
|
|
28
|
+
* @example separator: '\n\n===\n\n' produces `content\n\n===\n\nuser message`
|
|
29
|
+
*/
|
|
30
|
+
separator?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Result of collecting system content for fallback handling
|
|
34
|
+
*/
|
|
35
|
+
export interface SystemContentResult {
|
|
36
|
+
/** Combined system content from all sources */
|
|
37
|
+
combinedSystemContent: string | undefined;
|
|
38
|
+
/** Whether to use native system message support */
|
|
39
|
+
useNativeSystemMessage: boolean;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Generic message interface for system message handling
|
|
43
|
+
*/
|
|
44
|
+
export interface GenericMessage {
|
|
45
|
+
role: string;
|
|
46
|
+
content: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Default format options for system message fallback
|
|
50
|
+
*/
|
|
51
|
+
export declare const DEFAULT_SYSTEM_MESSAGE_FORMAT_OPTIONS: Required<SystemMessageFormatOptions>;
|
|
52
|
+
/**
|
|
53
|
+
* Formats system content according to the specified format options.
|
|
54
|
+
*
|
|
55
|
+
* @param systemContent - The system content to format
|
|
56
|
+
* @param userContent - The original user message content
|
|
57
|
+
* @param options - Format options (defaults to XML with 'system' tag)
|
|
58
|
+
* @returns The formatted combined content
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* // XML format (default)
|
|
63
|
+
* formatSystemContentForPrepend('Be helpful', 'Hello', { format: 'xml' });
|
|
64
|
+
* // Returns: '<system>\nBe helpful\n</system>\n\nHello'
|
|
65
|
+
*
|
|
66
|
+
* // Separator format (default separator is '\n\n---\n\n')
|
|
67
|
+
* formatSystemContentForPrepend('Be helpful', 'Hello', { format: 'separator' });
|
|
68
|
+
* // Returns: 'Be helpful\n\n---\n\nHello'
|
|
69
|
+
*
|
|
70
|
+
* // Custom separator (specify full separator including whitespace)
|
|
71
|
+
* formatSystemContentForPrepend('Be helpful', 'Hello', { format: 'separator', separator: '\n\n===\n\n' });
|
|
72
|
+
* // Returns: 'Be helpful\n\n===\n\nHello'
|
|
73
|
+
*
|
|
74
|
+
* // Plain format
|
|
75
|
+
* formatSystemContentForPrepend('Be helpful', 'Hello', { format: 'plain' });
|
|
76
|
+
* // Returns: 'Be helpful\n\nHello'
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export declare function formatSystemContentForPrepend(systemContent: string, userContent: string, options?: SystemMessageFormatOptions): string;
|
|
80
|
+
/**
|
|
81
|
+
* Collects and combines system content from multiple sources.
|
|
82
|
+
*
|
|
83
|
+
* Combines the request-level systemMessage with any inline system messages
|
|
84
|
+
* from the messages array into a single string.
|
|
85
|
+
*
|
|
86
|
+
* @param requestSystemMessage - The request.systemMessage field (if any)
|
|
87
|
+
* @param inlineSystemMessages - Array of system message contents from the messages array
|
|
88
|
+
* @param supportsSystemMessage - Whether the model supports native system messages
|
|
89
|
+
* @returns Object with combined content and whether to use native support
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* const { combinedSystemContent, useNativeSystemMessage } = collectSystemContent(
|
|
94
|
+
* 'You are helpful',
|
|
95
|
+
* ['Be concise'],
|
|
96
|
+
* false // Model doesn't support system messages
|
|
97
|
+
* );
|
|
98
|
+
* // combinedSystemContent = 'You are helpful\n\nBe concise'
|
|
99
|
+
* // useNativeSystemMessage = false
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export declare function collectSystemContent(requestSystemMessage: string | undefined, inlineSystemMessages: string[], supportsSystemMessage: boolean): SystemContentResult;
|
|
103
|
+
/**
|
|
104
|
+
* Prepends system content to the first user message in an array.
|
|
105
|
+
*
|
|
106
|
+
* This is used as a fallback for models that don't support native system
|
|
107
|
+
* instructions. The system content is formatted according to the options
|
|
108
|
+
* and prepended to the first user message.
|
|
109
|
+
*
|
|
110
|
+
* @param messages - Array of message objects with role and content
|
|
111
|
+
* @param systemContent - System content to prepend
|
|
112
|
+
* @param options - Format options (defaults to XML with 'system' tag)
|
|
113
|
+
* @returns The index of the modified message, or -1 if no user message found
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* const messages = [
|
|
118
|
+
* { role: 'user', content: 'Hello' },
|
|
119
|
+
* { role: 'assistant', content: 'Hi!' }
|
|
120
|
+
* ];
|
|
121
|
+
*
|
|
122
|
+
* // Default (XML format)
|
|
123
|
+
* prependSystemToFirstUserMessage(messages, 'Be helpful');
|
|
124
|
+
* // messages[0].content = '<system>\nBe helpful\n</system>\n\nHello'
|
|
125
|
+
*
|
|
126
|
+
* // Plain format
|
|
127
|
+
* prependSystemToFirstUserMessage(messages, 'Be helpful', { format: 'plain' });
|
|
128
|
+
* // messages[0].content = 'Be helpful\n\nHello'
|
|
129
|
+
*
|
|
130
|
+
* // Separator format (default separator is '\n\n---\n\n')
|
|
131
|
+
* prependSystemToFirstUserMessage(messages, 'Be helpful', { format: 'separator' });
|
|
132
|
+
* // messages[0].content = 'Be helpful\n\n---\n\nHello'
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export declare function prependSystemToFirstUserMessage<T extends GenericMessage>(messages: T[], systemContent: string, options?: SystemMessageFormatOptions): number;
|
|
136
|
+
/**
|
|
137
|
+
* Filters system messages from an array and returns non-system messages
|
|
138
|
+
* along with collected system content.
|
|
139
|
+
*
|
|
140
|
+
* This is a convenience function that combines message filtering with
|
|
141
|
+
* system content collection in a single pass.
|
|
142
|
+
*
|
|
143
|
+
* @param messages - Array of messages to process
|
|
144
|
+
* @param requestSystemMessage - Optional request-level system message
|
|
145
|
+
* @param supportsSystemMessage - Whether the model supports native system messages
|
|
146
|
+
* @returns Object with filtered messages and system content handling info
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```typescript
|
|
150
|
+
* const messages = [
|
|
151
|
+
* { role: 'system', content: 'Be helpful' },
|
|
152
|
+
* { role: 'user', content: 'Hello' }
|
|
153
|
+
* ];
|
|
154
|
+
* const result = processMessagesForSystemSupport(messages, undefined, false);
|
|
155
|
+
* // result.nonSystemMessages = [{ role: 'user', content: 'Hello' }]
|
|
156
|
+
* // result.systemContent.combinedSystemContent = 'Be helpful'
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export declare function processMessagesForSystemSupport<T extends GenericMessage>(messages: T[], requestSystemMessage: string | undefined, supportsSystemMessage: boolean): {
|
|
160
|
+
nonSystemMessages: T[];
|
|
161
|
+
systemContent: SystemContentResult;
|
|
162
|
+
};
|