genai-lite 0.3.3 → 0.4.1
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 +421 -51
- package/dist/index.d.ts +5 -0
- package/dist/index.js +8 -1
- package/dist/llm/LLMService.d.ts +29 -2
- package/dist/llm/LLMService.js +67 -36
- package/dist/llm/clients/LlamaCppClientAdapter.d.ts +116 -0
- package/dist/llm/clients/LlamaCppClientAdapter.js +289 -0
- package/dist/llm/clients/LlamaCppServerClient.d.ts +161 -0
- package/dist/llm/clients/LlamaCppServerClient.js +192 -0
- package/dist/llm/config.d.ts +12 -0
- package/dist/llm/config.js +81 -4
- package/dist/llm/services/ModelResolver.js +13 -13
- package/dist/llm/services/SettingsManager.js +17 -11
- package/dist/llm/types.d.ts +87 -22
- package/dist/prompting/parser.d.ts +2 -2
- package/dist/prompting/parser.js +2 -2
- package/dist/providers/fromEnvironment.d.ts +4 -0
- package/dist/providers/fromEnvironment.js +8 -0
- package/package.json +1 -1
- package/dist/llm/LLMService.createMessages.test.d.ts +0 -4
- package/dist/llm/LLMService.createMessages.test.js +0 -364
- package/dist/llm/LLMService.original.d.ts +0 -147
- package/dist/llm/LLMService.original.js +0 -656
- package/dist/llm/LLMService.prepareMessage.test.d.ts +0 -1
- package/dist/llm/LLMService.prepareMessage.test.js +0 -303
- package/dist/llm/LLMService.presets.test.d.ts +0 -1
- package/dist/llm/LLMService.presets.test.js +0 -210
- package/dist/llm/LLMService.sendMessage.preset.test.d.ts +0 -1
- package/dist/llm/LLMService.sendMessage.preset.test.js +0 -153
- package/dist/llm/LLMService.test.d.ts +0 -1
- package/dist/llm/LLMService.test.js +0 -620
- package/dist/llm/clients/AnthropicClientAdapter.test.d.ts +0 -1
- package/dist/llm/clients/AnthropicClientAdapter.test.js +0 -273
- package/dist/llm/clients/GeminiClientAdapter.test.d.ts +0 -1
- package/dist/llm/clients/GeminiClientAdapter.test.js +0 -405
- package/dist/llm/clients/MockClientAdapter.test.d.ts +0 -1
- package/dist/llm/clients/MockClientAdapter.test.js +0 -250
- package/dist/llm/clients/OpenAIClientAdapter.test.d.ts +0 -1
- package/dist/llm/clients/OpenAIClientAdapter.test.js +0 -258
- package/dist/llm/clients/adapterErrorUtils.test.d.ts +0 -1
- package/dist/llm/clients/adapterErrorUtils.test.js +0 -123
- package/dist/llm/config.test.d.ts +0 -1
- package/dist/llm/config.test.js +0 -176
- package/dist/llm/services/AdapterRegistry.test.d.ts +0 -1
- package/dist/llm/services/AdapterRegistry.test.js +0 -239
- package/dist/llm/services/ModelResolver.test.d.ts +0 -1
- package/dist/llm/services/ModelResolver.test.js +0 -158
- package/dist/llm/services/PresetManager.test.d.ts +0 -1
- package/dist/llm/services/PresetManager.test.js +0 -210
- package/dist/llm/services/RequestValidator.test.d.ts +0 -1
- package/dist/llm/services/RequestValidator.test.js +0 -159
- package/dist/llm/services/SettingsManager.test.d.ts +0 -1
- package/dist/llm/services/SettingsManager.test.js +0 -266
- package/dist/prompting/builder.d.ts +0 -38
- package/dist/prompting/builder.js +0 -63
- package/dist/prompting/builder.test.d.ts +0 -4
- package/dist/prompting/builder.test.js +0 -109
- package/dist/prompting/content.test.d.ts +0 -4
- package/dist/prompting/content.test.js +0 -212
- package/dist/prompting/parser.test.d.ts +0 -4
- package/dist/prompting/parser.test.js +0 -464
- package/dist/prompting/template.test.d.ts +0 -1
- package/dist/prompting/template.test.js +0 -250
- package/dist/providers/fromEnvironment.test.d.ts +0 -1
- package/dist/providers/fromEnvironment.test.js +0 -46
|
@@ -1,656 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// AI Summary: Main process service for LLM operations, integrating with ApiKeyProvider for secure key access.
|
|
3
|
-
// Orchestrates LLM requests through provider-specific client adapters with proper error handling.
|
|
4
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
6
|
-
};
|
|
7
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.LLMService = void 0;
|
|
9
|
-
const MockClientAdapter_1 = require("./clients/MockClientAdapter");
|
|
10
|
-
const config_1 = require("./config");
|
|
11
|
-
const presets_json_1 = __importDefault(require("../config/presets.json"));
|
|
12
|
-
const template_1 = require("../prompting/template");
|
|
13
|
-
/**
|
|
14
|
-
* Main process service for LLM operations
|
|
15
|
-
*
|
|
16
|
-
* This service:
|
|
17
|
-
* - Manages LLM provider client adapters
|
|
18
|
-
* - Integrates with ApiKeyServiceMain for secure API key access
|
|
19
|
-
* - Validates requests and applies default settings
|
|
20
|
-
* - Routes requests to appropriate provider adapters
|
|
21
|
-
* - Handles errors and provides standardized responses
|
|
22
|
-
* - Provides configurable model presets for common use cases
|
|
23
|
-
*/
|
|
24
|
-
class LLMService {
|
|
25
|
-
constructor(getApiKey, options = {}) {
|
|
26
|
-
this.getApiKey = getApiKey;
|
|
27
|
-
this.clientAdapters = new Map();
|
|
28
|
-
this.mockClientAdapter = new MockClientAdapter_1.MockClientAdapter();
|
|
29
|
-
// Initialize presets based on mode
|
|
30
|
-
const finalPresets = new Map();
|
|
31
|
-
const customPresets = options.presets || [];
|
|
32
|
-
const mode = options.presetMode || 'extend';
|
|
33
|
-
if (mode === 'replace') {
|
|
34
|
-
// Replace Mode: Only use custom presets.
|
|
35
|
-
for (const preset of customPresets) {
|
|
36
|
-
finalPresets.set(preset.id, preset);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
// Extend Mode: Load defaults first, then add/override.
|
|
41
|
-
for (const preset of presets_json_1.default) {
|
|
42
|
-
finalPresets.set(preset.id, preset);
|
|
43
|
-
}
|
|
44
|
-
for (const preset of customPresets) {
|
|
45
|
-
finalPresets.set(preset.id, preset);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
this.presets = Array.from(finalPresets.values());
|
|
49
|
-
// Dynamically register client adapters based on configuration
|
|
50
|
-
let registeredCount = 0;
|
|
51
|
-
const successfullyRegisteredProviders = [];
|
|
52
|
-
for (const provider of config_1.SUPPORTED_PROVIDERS) {
|
|
53
|
-
const AdapterClass = config_1.ADAPTER_CONSTRUCTORS[provider.id];
|
|
54
|
-
if (AdapterClass) {
|
|
55
|
-
try {
|
|
56
|
-
const adapterConfig = config_1.ADAPTER_CONFIGS[provider.id];
|
|
57
|
-
const adapterInstance = new AdapterClass(adapterConfig);
|
|
58
|
-
this.registerClientAdapter(provider.id, adapterInstance);
|
|
59
|
-
registeredCount++;
|
|
60
|
-
successfullyRegisteredProviders.push(provider.id);
|
|
61
|
-
}
|
|
62
|
-
catch (error) {
|
|
63
|
-
console.error(`LLMService: Failed to instantiate adapter for provider '${provider.id}'. This provider will use the mock adapter. Error:`, error);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
console.warn(`LLMService: No adapter constructor found for supported provider '${provider.id}'. This provider will use the mock adapter as a fallback.`);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
if (registeredCount > 0) {
|
|
71
|
-
console.log(`LLMService: Initialized with ${registeredCount} dynamically registered adapter(s) for: ${successfullyRegisteredProviders.join(", ")}.`);
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
console.log(`LLMService: No real adapters were dynamically registered. All providers will use the mock adapter.`);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Gets list of supported LLM providers
|
|
79
|
-
*
|
|
80
|
-
* @returns Promise resolving to array of provider information
|
|
81
|
-
*/
|
|
82
|
-
async getProviders() {
|
|
83
|
-
console.log("LLMService.getProviders called");
|
|
84
|
-
return [...config_1.SUPPORTED_PROVIDERS]; // Return a copy to prevent external modification
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Gets list of supported models for a specific provider
|
|
88
|
-
*
|
|
89
|
-
* @param providerId - The provider ID to get models for
|
|
90
|
-
* @returns Promise resolving to array of model information
|
|
91
|
-
*/
|
|
92
|
-
async getModels(providerId) {
|
|
93
|
-
console.log(`LLMService.getModels called for provider: ${providerId}`);
|
|
94
|
-
// Validate provider exists
|
|
95
|
-
if (!(0, config_1.isProviderSupported)(providerId)) {
|
|
96
|
-
console.warn(`Requested models for unsupported provider: ${providerId}`);
|
|
97
|
-
return [];
|
|
98
|
-
}
|
|
99
|
-
const models = (0, config_1.getModelsByProvider)(providerId);
|
|
100
|
-
console.log(`Found ${models.length} models for provider: ${providerId}`);
|
|
101
|
-
return [...models]; // Return a copy to prevent external modification
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Sends a chat message to an LLM provider
|
|
105
|
-
*
|
|
106
|
-
* @param request - The LLM chat request
|
|
107
|
-
* @returns Promise resolving to either success or failure response
|
|
108
|
-
*/
|
|
109
|
-
async sendMessage(request) {
|
|
110
|
-
console.log(`LLMService.sendMessage called with presetId: ${request.presetId}, provider: ${request.providerId}, model: ${request.modelId}`);
|
|
111
|
-
try {
|
|
112
|
-
// Resolve model information from preset or direct IDs
|
|
113
|
-
const resolved = this.resolveModelInfo(request);
|
|
114
|
-
if (resolved.error) {
|
|
115
|
-
return resolved.error;
|
|
116
|
-
}
|
|
117
|
-
const { providerId, modelId, modelInfo, settings: resolvedSettings } = resolved;
|
|
118
|
-
// Create a proper LLMChatRequest with resolved values
|
|
119
|
-
const resolvedRequest = {
|
|
120
|
-
...request,
|
|
121
|
-
providerId: providerId,
|
|
122
|
-
modelId: modelId,
|
|
123
|
-
};
|
|
124
|
-
// Provider and model validation already done by resolveModelInfo
|
|
125
|
-
// Validate basic request structure
|
|
126
|
-
const structureValidationResult = this.validateRequestStructure(resolvedRequest);
|
|
127
|
-
if (structureValidationResult) {
|
|
128
|
-
return structureValidationResult;
|
|
129
|
-
}
|
|
130
|
-
// Validate settings if provided
|
|
131
|
-
const combinedSettings = { ...resolvedSettings, ...request.settings };
|
|
132
|
-
if (combinedSettings) {
|
|
133
|
-
const settingsValidationErrors = (0, config_1.validateLLMSettings)(combinedSettings);
|
|
134
|
-
if (settingsValidationErrors.length > 0) {
|
|
135
|
-
return {
|
|
136
|
-
provider: providerId,
|
|
137
|
-
model: modelId,
|
|
138
|
-
error: {
|
|
139
|
-
message: `Invalid settings: ${settingsValidationErrors.join(", ")}`,
|
|
140
|
-
code: "INVALID_SETTINGS",
|
|
141
|
-
type: "validation_error",
|
|
142
|
-
},
|
|
143
|
-
object: "error",
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
// Apply model-specific defaults and merge with user settings
|
|
148
|
-
const finalSettings = this.mergeSettingsForModel(modelId, providerId, combinedSettings);
|
|
149
|
-
// Validate reasoning settings for model capabilities
|
|
150
|
-
const reasoningValidation = this.validateReasoningSettings(modelInfo, finalSettings.reasoning, resolvedRequest);
|
|
151
|
-
if (reasoningValidation) {
|
|
152
|
-
return reasoningValidation;
|
|
153
|
-
}
|
|
154
|
-
// Filter out unsupported parameters based on model and provider configuration
|
|
155
|
-
let filteredSettings = { ...finalSettings }; // Create a mutable copy
|
|
156
|
-
// Get provider info for parameter filtering (modelInfo is already available from earlier validation)
|
|
157
|
-
const providerInfo = (0, config_1.getProviderById)(providerId);
|
|
158
|
-
const paramsToExclude = new Set();
|
|
159
|
-
// Add provider-level exclusions
|
|
160
|
-
if (providerInfo?.unsupportedParameters) {
|
|
161
|
-
providerInfo.unsupportedParameters.forEach((param) => paramsToExclude.add(param));
|
|
162
|
-
}
|
|
163
|
-
// Add model-level exclusions (these will be added to any provider-level ones)
|
|
164
|
-
if (modelInfo?.unsupportedParameters) {
|
|
165
|
-
modelInfo.unsupportedParameters.forEach((param) => paramsToExclude.add(param));
|
|
166
|
-
}
|
|
167
|
-
if (paramsToExclude.size > 0) {
|
|
168
|
-
console.log(`LLMService: Potential parameters to exclude for provider '${providerId}', model '${modelId}':`, Array.from(paramsToExclude));
|
|
169
|
-
}
|
|
170
|
-
paramsToExclude.forEach((param) => {
|
|
171
|
-
// Check if the parameter key actually exists in filteredSettings before trying to delete
|
|
172
|
-
// (it might have been undefined initially and thus not part of finalSettings depending on merge logic)
|
|
173
|
-
// Using 'in' operator is robust for checking presence of properties, including those from prototype chain.
|
|
174
|
-
// For direct properties of an object, hasOwnProperty is more specific.
|
|
175
|
-
// Given finalSettings is Required<LLMSettings>, all keys should be present, potentially as undefined.
|
|
176
|
-
if (param in filteredSettings) {
|
|
177
|
-
console.log(`LLMService: Removing excluded parameter '${String(param)}' for provider '${providerId}', model '${modelId}'. Value was:`, filteredSettings[param]);
|
|
178
|
-
delete filteredSettings[param]; // Cast to allow deletion
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
181
|
-
// This case should ideally not happen if finalSettings truly is Required<LLMSettings>
|
|
182
|
-
// and mergeSettingsForModel ensures all keys are present (even if undefined).
|
|
183
|
-
console.log(`LLMService: Parameter '${String(param)}' marked for exclusion was not found in settings for provider '${providerId}', model '${modelId}'.`);
|
|
184
|
-
}
|
|
185
|
-
});
|
|
186
|
-
// Handle reasoning settings for models that don't support it
|
|
187
|
-
// This happens after validateReasoningSettings so we know it's safe to strip
|
|
188
|
-
if (!modelInfo.reasoning?.supported && filteredSettings.reasoning) {
|
|
189
|
-
console.log(`LLMService: Removing reasoning settings for non-reasoning model ${modelId}`);
|
|
190
|
-
delete filteredSettings.reasoning;
|
|
191
|
-
}
|
|
192
|
-
const internalRequest = {
|
|
193
|
-
...resolvedRequest,
|
|
194
|
-
settings: filteredSettings,
|
|
195
|
-
};
|
|
196
|
-
console.log(`Processing LLM request with (potentially filtered) settings:`, {
|
|
197
|
-
provider: providerId,
|
|
198
|
-
model: modelId,
|
|
199
|
-
settings: filteredSettings,
|
|
200
|
-
messageCount: resolvedRequest.messages.length,
|
|
201
|
-
});
|
|
202
|
-
console.log(`Processing LLM request: ${resolvedRequest.messages.length} messages, model: ${modelId}`);
|
|
203
|
-
// Get client adapter
|
|
204
|
-
const clientAdapter = this.getClientAdapter(providerId);
|
|
205
|
-
// Use ApiKeyProvider to get the API key and make the request
|
|
206
|
-
try {
|
|
207
|
-
const apiKey = await this.getApiKey(providerId);
|
|
208
|
-
if (!apiKey) {
|
|
209
|
-
return {
|
|
210
|
-
provider: providerId,
|
|
211
|
-
model: modelId,
|
|
212
|
-
error: {
|
|
213
|
-
message: `API key for provider '${providerId}' could not be retrieved. Ensure your ApiKeyProvider is configured correctly.`,
|
|
214
|
-
code: "API_KEY_ERROR",
|
|
215
|
-
type: "authentication_error",
|
|
216
|
-
},
|
|
217
|
-
object: "error",
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
console.log(`Making LLM request with ${clientAdapter.constructor.name} for provider: ${providerId}`);
|
|
221
|
-
const result = await clientAdapter.sendMessage(internalRequest, apiKey);
|
|
222
|
-
console.log(`LLM request completed successfully for model: ${modelId}`);
|
|
223
|
-
return result;
|
|
224
|
-
}
|
|
225
|
-
catch (error) {
|
|
226
|
-
console.error("Error in LLMService.sendMessage:", error);
|
|
227
|
-
return {
|
|
228
|
-
provider: providerId,
|
|
229
|
-
model: modelId,
|
|
230
|
-
error: {
|
|
231
|
-
message: error instanceof Error
|
|
232
|
-
? error.message
|
|
233
|
-
: "An unknown error occurred during message sending.",
|
|
234
|
-
code: "PROVIDER_ERROR",
|
|
235
|
-
type: "server_error",
|
|
236
|
-
providerError: error,
|
|
237
|
-
},
|
|
238
|
-
object: "error",
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
catch (error) {
|
|
243
|
-
console.error("Error in LLMService.sendMessage (outer):", error);
|
|
244
|
-
return {
|
|
245
|
-
provider: request.providerId || request.presetId || 'unknown',
|
|
246
|
-
model: request.modelId || request.presetId || 'unknown',
|
|
247
|
-
error: {
|
|
248
|
-
message: error instanceof Error
|
|
249
|
-
? error.message
|
|
250
|
-
: "An unknown error occurred.",
|
|
251
|
-
code: "UNEXPECTED_ERROR",
|
|
252
|
-
type: "server_error",
|
|
253
|
-
providerError: error,
|
|
254
|
-
},
|
|
255
|
-
object: "error",
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* Validates basic LLM request structure
|
|
261
|
-
*
|
|
262
|
-
* @param request - The request to validate
|
|
263
|
-
* @returns LLMFailureResponse if validation fails, null if valid
|
|
264
|
-
*/
|
|
265
|
-
validateRequestStructure(request) {
|
|
266
|
-
// Basic request structure validation
|
|
267
|
-
if (!request.messages ||
|
|
268
|
-
!Array.isArray(request.messages) ||
|
|
269
|
-
request.messages.length === 0) {
|
|
270
|
-
return {
|
|
271
|
-
provider: request.providerId || request.presetId || 'unknown',
|
|
272
|
-
model: request.modelId || request.presetId || 'unknown',
|
|
273
|
-
error: {
|
|
274
|
-
message: "Request must contain at least one message",
|
|
275
|
-
code: "INVALID_REQUEST",
|
|
276
|
-
type: "validation_error",
|
|
277
|
-
},
|
|
278
|
-
object: "error",
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
// Validate message structure
|
|
282
|
-
for (let i = 0; i < request.messages.length; i++) {
|
|
283
|
-
const message = request.messages[i];
|
|
284
|
-
if (!message.role || !message.content) {
|
|
285
|
-
return {
|
|
286
|
-
provider: request.providerId || ('presetId' in request ? request.presetId : undefined) || 'unknown',
|
|
287
|
-
model: request.modelId || ('presetId' in request ? request.presetId : undefined) || 'unknown',
|
|
288
|
-
error: {
|
|
289
|
-
message: `Message at index ${i} must have both 'role' and 'content' properties`,
|
|
290
|
-
code: "INVALID_MESSAGE",
|
|
291
|
-
type: "validation_error",
|
|
292
|
-
},
|
|
293
|
-
object: "error",
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
if (!["user", "assistant", "system"].includes(message.role)) {
|
|
297
|
-
return {
|
|
298
|
-
provider: request.providerId || ('presetId' in request ? request.presetId : undefined) || 'unknown',
|
|
299
|
-
model: request.modelId || ('presetId' in request ? request.presetId : undefined) || 'unknown',
|
|
300
|
-
error: {
|
|
301
|
-
message: `Invalid message role '${message.role}' at index ${i}. Must be 'user', 'assistant', or 'system'`,
|
|
302
|
-
code: "INVALID_MESSAGE_ROLE",
|
|
303
|
-
type: "validation_error",
|
|
304
|
-
},
|
|
305
|
-
object: "error",
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
return null; // Request is valid
|
|
310
|
-
}
|
|
311
|
-
/**
|
|
312
|
-
* Validates reasoning settings against model capabilities
|
|
313
|
-
*
|
|
314
|
-
* @param modelInfo - The model information
|
|
315
|
-
* @param reasoning - The reasoning settings to validate
|
|
316
|
-
* @param request - The original request for error context
|
|
317
|
-
* @returns LLMFailureResponse if validation fails, null if valid
|
|
318
|
-
*/
|
|
319
|
-
validateReasoningSettings(modelInfo, reasoning, request) {
|
|
320
|
-
// If no reasoning settings provided, nothing to validate
|
|
321
|
-
if (!reasoning) {
|
|
322
|
-
return null;
|
|
323
|
-
}
|
|
324
|
-
// If model doesn't support reasoning
|
|
325
|
-
if (!modelInfo.reasoning?.supported) {
|
|
326
|
-
// Check if user is trying to enable reasoning
|
|
327
|
-
const tryingToEnableReasoning = reasoning.enabled === true ||
|
|
328
|
-
reasoning.effort !== undefined ||
|
|
329
|
-
(reasoning.maxTokens !== undefined && reasoning.maxTokens > 0);
|
|
330
|
-
if (tryingToEnableReasoning) {
|
|
331
|
-
return {
|
|
332
|
-
provider: request.providerId,
|
|
333
|
-
model: request.modelId,
|
|
334
|
-
error: {
|
|
335
|
-
message: `Model ${request.modelId} does not support reasoning/thinking`,
|
|
336
|
-
type: 'validation_error',
|
|
337
|
-
code: 'reasoning_not_supported'
|
|
338
|
-
},
|
|
339
|
-
object: 'error'
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
// Otherwise, user is explicitly disabling reasoning - this is fine
|
|
343
|
-
// The reasoning settings will be stripped later
|
|
344
|
-
}
|
|
345
|
-
return null;
|
|
346
|
-
}
|
|
347
|
-
/**
|
|
348
|
-
* Merges request settings with model-specific and global defaults
|
|
349
|
-
*
|
|
350
|
-
* @param modelId - The model ID to get defaults for
|
|
351
|
-
* @param providerId - The provider ID to get defaults for
|
|
352
|
-
* @param requestSettings - Settings from the request
|
|
353
|
-
* @returns Complete settings object with all required fields
|
|
354
|
-
*/
|
|
355
|
-
mergeSettingsForModel(modelId, providerId, requestSettings) {
|
|
356
|
-
// Get model-specific defaults
|
|
357
|
-
const modelDefaults = (0, config_1.getDefaultSettingsForModel)(modelId, providerId);
|
|
358
|
-
// Merge with user-provided settings (user settings take precedence)
|
|
359
|
-
const mergedSettings = {
|
|
360
|
-
temperature: requestSettings?.temperature ?? modelDefaults.temperature,
|
|
361
|
-
maxTokens: requestSettings?.maxTokens ?? modelDefaults.maxTokens,
|
|
362
|
-
topP: requestSettings?.topP ?? modelDefaults.topP,
|
|
363
|
-
stopSequences: requestSettings?.stopSequences ?? modelDefaults.stopSequences,
|
|
364
|
-
frequencyPenalty: requestSettings?.frequencyPenalty ?? modelDefaults.frequencyPenalty,
|
|
365
|
-
presencePenalty: requestSettings?.presencePenalty ?? modelDefaults.presencePenalty,
|
|
366
|
-
user: requestSettings?.user ?? modelDefaults.user,
|
|
367
|
-
supportsSystemMessage: requestSettings?.supportsSystemMessage ??
|
|
368
|
-
modelDefaults.supportsSystemMessage,
|
|
369
|
-
geminiSafetySettings: requestSettings?.geminiSafetySettings ??
|
|
370
|
-
modelDefaults.geminiSafetySettings,
|
|
371
|
-
reasoning: {
|
|
372
|
-
...modelDefaults.reasoning,
|
|
373
|
-
...requestSettings?.reasoning,
|
|
374
|
-
},
|
|
375
|
-
};
|
|
376
|
-
// Log the final settings for debugging
|
|
377
|
-
console.log(`Merged settings for ${providerId}/${modelId}:`, {
|
|
378
|
-
temperature: mergedSettings.temperature,
|
|
379
|
-
maxTokens: mergedSettings.maxTokens,
|
|
380
|
-
topP: mergedSettings.topP,
|
|
381
|
-
hasStopSequences: mergedSettings.stopSequences.length > 0,
|
|
382
|
-
frequencyPenalty: mergedSettings.frequencyPenalty,
|
|
383
|
-
presencePenalty: mergedSettings.presencePenalty,
|
|
384
|
-
hasUser: !!mergedSettings.user,
|
|
385
|
-
geminiSafetySettingsCount: mergedSettings.geminiSafetySettings.length,
|
|
386
|
-
reasoning: mergedSettings.reasoning,
|
|
387
|
-
});
|
|
388
|
-
return mergedSettings;
|
|
389
|
-
}
|
|
390
|
-
/**
|
|
391
|
-
* Gets the appropriate client adapter for a provider
|
|
392
|
-
*
|
|
393
|
-
* @param providerId - The provider ID
|
|
394
|
-
* @returns The client adapter to use
|
|
395
|
-
*/
|
|
396
|
-
getClientAdapter(providerId) {
|
|
397
|
-
// Check for registered real adapters first
|
|
398
|
-
const registeredAdapter = this.clientAdapters.get(providerId);
|
|
399
|
-
if (registeredAdapter) {
|
|
400
|
-
console.log(`Using registered adapter for provider: ${providerId}`);
|
|
401
|
-
return registeredAdapter;
|
|
402
|
-
}
|
|
403
|
-
// Fall back to mock adapter for unsupported providers
|
|
404
|
-
console.log(`No real adapter found for ${providerId}, using mock adapter`);
|
|
405
|
-
return this.mockClientAdapter;
|
|
406
|
-
}
|
|
407
|
-
/**
|
|
408
|
-
* Registers a client adapter for a specific provider
|
|
409
|
-
*
|
|
410
|
-
* @param providerId - The provider ID
|
|
411
|
-
* @param adapter - The client adapter implementation
|
|
412
|
-
*/
|
|
413
|
-
registerClientAdapter(providerId, adapter) {
|
|
414
|
-
this.clientAdapters.set(providerId, adapter);
|
|
415
|
-
console.log(`Registered client adapter for provider: ${providerId}`);
|
|
416
|
-
}
|
|
417
|
-
/**
|
|
418
|
-
* Gets information about registered adapters
|
|
419
|
-
*
|
|
420
|
-
* @returns Map of provider IDs to adapter info
|
|
421
|
-
*/
|
|
422
|
-
getRegisteredAdapters() {
|
|
423
|
-
const adapterInfo = new Map();
|
|
424
|
-
for (const [providerId, adapter] of this.clientAdapters.entries()) {
|
|
425
|
-
adapterInfo.set(providerId, {
|
|
426
|
-
providerId,
|
|
427
|
-
hasAdapter: true,
|
|
428
|
-
adapterInfo: adapter.getAdapterInfo?.() || { name: "Unknown Adapter" },
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
return adapterInfo;
|
|
432
|
-
}
|
|
433
|
-
/**
|
|
434
|
-
* Gets a summary of available providers and their adapter status
|
|
435
|
-
*
|
|
436
|
-
* @returns Summary of provider availability
|
|
437
|
-
*/
|
|
438
|
-
getProviderSummary() {
|
|
439
|
-
const availableProviders = [];
|
|
440
|
-
const unavailableProviders = [];
|
|
441
|
-
for (const provider of config_1.SUPPORTED_PROVIDERS) {
|
|
442
|
-
if (this.clientAdapters.has(provider.id)) {
|
|
443
|
-
availableProviders.push(provider.id);
|
|
444
|
-
}
|
|
445
|
-
else {
|
|
446
|
-
unavailableProviders.push(provider.id);
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
return {
|
|
450
|
-
totalProviders: config_1.SUPPORTED_PROVIDERS.length,
|
|
451
|
-
providersWithAdapters: availableProviders.length,
|
|
452
|
-
availableProviders,
|
|
453
|
-
unavailableProviders,
|
|
454
|
-
};
|
|
455
|
-
}
|
|
456
|
-
/**
|
|
457
|
-
* Gets all configured model presets
|
|
458
|
-
*
|
|
459
|
-
* @returns Array of model presets
|
|
460
|
-
*/
|
|
461
|
-
getPresets() {
|
|
462
|
-
return [...this.presets]; // Return a copy to prevent external modification
|
|
463
|
-
}
|
|
464
|
-
/**
|
|
465
|
-
* Resolves model information from either a preset ID or provider/model IDs
|
|
466
|
-
*
|
|
467
|
-
* @private
|
|
468
|
-
* @param options Options containing either presetId or providerId/modelId
|
|
469
|
-
* @returns Resolved model info and settings or error response
|
|
470
|
-
*/
|
|
471
|
-
resolveModelInfo(options) {
|
|
472
|
-
// If presetId is provided, use it
|
|
473
|
-
if (options.presetId) {
|
|
474
|
-
const preset = this.presets.find(p => p.id === options.presetId);
|
|
475
|
-
if (!preset) {
|
|
476
|
-
return {
|
|
477
|
-
error: {
|
|
478
|
-
provider: 'unknown',
|
|
479
|
-
model: 'unknown',
|
|
480
|
-
error: {
|
|
481
|
-
message: `Preset not found: ${options.presetId}`,
|
|
482
|
-
code: 'PRESET_NOT_FOUND',
|
|
483
|
-
type: 'validation_error',
|
|
484
|
-
},
|
|
485
|
-
object: 'error',
|
|
486
|
-
}
|
|
487
|
-
};
|
|
488
|
-
}
|
|
489
|
-
const modelInfo = (0, config_1.getModelById)(preset.modelId, preset.providerId);
|
|
490
|
-
if (!modelInfo) {
|
|
491
|
-
return {
|
|
492
|
-
error: {
|
|
493
|
-
provider: preset.providerId,
|
|
494
|
-
model: preset.modelId,
|
|
495
|
-
error: {
|
|
496
|
-
message: `Model not found for preset: ${options.presetId}`,
|
|
497
|
-
code: 'MODEL_NOT_FOUND',
|
|
498
|
-
type: 'validation_error',
|
|
499
|
-
},
|
|
500
|
-
object: 'error',
|
|
501
|
-
}
|
|
502
|
-
};
|
|
503
|
-
}
|
|
504
|
-
// Merge preset settings with user settings
|
|
505
|
-
const settings = {
|
|
506
|
-
...preset.settings,
|
|
507
|
-
...options.settings
|
|
508
|
-
};
|
|
509
|
-
return {
|
|
510
|
-
providerId: preset.providerId,
|
|
511
|
-
modelId: preset.modelId,
|
|
512
|
-
modelInfo,
|
|
513
|
-
settings
|
|
514
|
-
};
|
|
515
|
-
}
|
|
516
|
-
// Otherwise, use providerId and modelId
|
|
517
|
-
if (!options.providerId || !options.modelId) {
|
|
518
|
-
return {
|
|
519
|
-
error: {
|
|
520
|
-
provider: options.providerId || 'unknown',
|
|
521
|
-
model: options.modelId || 'unknown',
|
|
522
|
-
error: {
|
|
523
|
-
message: 'Either presetId or both providerId and modelId must be provided',
|
|
524
|
-
code: 'INVALID_MODEL_SELECTION',
|
|
525
|
-
type: 'validation_error',
|
|
526
|
-
},
|
|
527
|
-
object: 'error',
|
|
528
|
-
}
|
|
529
|
-
};
|
|
530
|
-
}
|
|
531
|
-
// Check if provider is supported first
|
|
532
|
-
if (!(0, config_1.isProviderSupported)(options.providerId)) {
|
|
533
|
-
return {
|
|
534
|
-
error: {
|
|
535
|
-
provider: options.providerId,
|
|
536
|
-
model: options.modelId,
|
|
537
|
-
error: {
|
|
538
|
-
message: `Unsupported provider: ${options.providerId}. Supported providers: ${config_1.SUPPORTED_PROVIDERS.map((p) => p.id).join(', ')}`,
|
|
539
|
-
code: 'UNSUPPORTED_PROVIDER',
|
|
540
|
-
type: 'validation_error',
|
|
541
|
-
},
|
|
542
|
-
object: 'error',
|
|
543
|
-
}
|
|
544
|
-
};
|
|
545
|
-
}
|
|
546
|
-
const modelInfo = (0, config_1.getModelById)(options.modelId, options.providerId);
|
|
547
|
-
if (!modelInfo) {
|
|
548
|
-
return {
|
|
549
|
-
error: {
|
|
550
|
-
provider: options.providerId,
|
|
551
|
-
model: options.modelId,
|
|
552
|
-
error: {
|
|
553
|
-
message: `Unsupported model: ${options.modelId} for provider: ${options.providerId}`,
|
|
554
|
-
code: 'UNSUPPORTED_MODEL',
|
|
555
|
-
type: 'validation_error',
|
|
556
|
-
},
|
|
557
|
-
object: 'error',
|
|
558
|
-
}
|
|
559
|
-
};
|
|
560
|
-
}
|
|
561
|
-
return {
|
|
562
|
-
providerId: options.providerId,
|
|
563
|
-
modelId: options.modelId,
|
|
564
|
-
modelInfo,
|
|
565
|
-
settings: options.settings
|
|
566
|
-
};
|
|
567
|
-
}
|
|
568
|
-
/**
|
|
569
|
-
* Prepares messages with model context for template rendering
|
|
570
|
-
*
|
|
571
|
-
* This method resolves model information from either a preset or direct provider/model IDs,
|
|
572
|
-
* then renders a template with model context variables injected, or returns pre-built messages
|
|
573
|
-
* with the model context separately.
|
|
574
|
-
*
|
|
575
|
-
* @param options Options for preparing messages
|
|
576
|
-
* @returns Promise resolving to prepared messages and model context
|
|
577
|
-
*
|
|
578
|
-
* @example
|
|
579
|
-
* ```typescript
|
|
580
|
-
* const { messages } = await llm.prepareMessage({
|
|
581
|
-
* template: 'Help me {{ thinking_enabled ? "think through" : "solve" }} this: {{ problem }}',
|
|
582
|
-
* variables: { problem: 'complex algorithm' },
|
|
583
|
-
* presetId: 'anthropic-claude-3-7-sonnet-20250219-thinking'
|
|
584
|
-
* });
|
|
585
|
-
* ```
|
|
586
|
-
*/
|
|
587
|
-
async prepareMessage(options) {
|
|
588
|
-
console.log('LLMService.prepareMessage called');
|
|
589
|
-
// Validate input
|
|
590
|
-
if (!options.template && !options.messages) {
|
|
591
|
-
return {
|
|
592
|
-
provider: 'unknown',
|
|
593
|
-
model: 'unknown',
|
|
594
|
-
error: {
|
|
595
|
-
message: 'Either template or messages must be provided',
|
|
596
|
-
code: 'INVALID_INPUT',
|
|
597
|
-
type: 'validation_error',
|
|
598
|
-
},
|
|
599
|
-
object: 'error',
|
|
600
|
-
};
|
|
601
|
-
}
|
|
602
|
-
// Resolve model information
|
|
603
|
-
const resolved = this.resolveModelInfo(options);
|
|
604
|
-
if (resolved.error) {
|
|
605
|
-
return resolved.error;
|
|
606
|
-
}
|
|
607
|
-
const { providerId, modelId, modelInfo, settings } = resolved;
|
|
608
|
-
// Merge settings with model defaults
|
|
609
|
-
const mergedSettings = this.mergeSettingsForModel(modelId, providerId, settings);
|
|
610
|
-
// Create model context
|
|
611
|
-
const modelContext = {
|
|
612
|
-
thinking_enabled: !!(modelInfo.reasoning?.supported &&
|
|
613
|
-
(mergedSettings.reasoning?.enabled === true ||
|
|
614
|
-
(modelInfo.reasoning?.enabledByDefault && mergedSettings.reasoning?.enabled !== false))),
|
|
615
|
-
thinking_available: !!modelInfo.reasoning?.supported,
|
|
616
|
-
model_id: modelId,
|
|
617
|
-
provider_id: providerId,
|
|
618
|
-
reasoning_effort: mergedSettings.reasoning?.effort,
|
|
619
|
-
reasoning_max_tokens: mergedSettings.reasoning?.maxTokens,
|
|
620
|
-
};
|
|
621
|
-
// Prepare messages
|
|
622
|
-
let messages;
|
|
623
|
-
if (options.template) {
|
|
624
|
-
// Render template with variables and model context
|
|
625
|
-
const allVariables = {
|
|
626
|
-
...options.variables,
|
|
627
|
-
...modelContext, // Inject model context at root level
|
|
628
|
-
};
|
|
629
|
-
try {
|
|
630
|
-
const content = (0, template_1.renderTemplate)(options.template, allVariables);
|
|
631
|
-
messages = [{ role: 'user', content }];
|
|
632
|
-
}
|
|
633
|
-
catch (error) {
|
|
634
|
-
return {
|
|
635
|
-
provider: providerId,
|
|
636
|
-
model: modelId,
|
|
637
|
-
error: {
|
|
638
|
-
message: `Template rendering failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
639
|
-
code: 'TEMPLATE_ERROR',
|
|
640
|
-
type: 'validation_error',
|
|
641
|
-
},
|
|
642
|
-
object: 'error',
|
|
643
|
-
};
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
else {
|
|
647
|
-
// Use pre-built messages
|
|
648
|
-
messages = options.messages;
|
|
649
|
-
}
|
|
650
|
-
return {
|
|
651
|
-
messages,
|
|
652
|
-
modelContext,
|
|
653
|
-
};
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
exports.LLMService = LLMService;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|