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.
Files changed (65) hide show
  1. package/README.md +421 -51
  2. package/dist/index.d.ts +5 -0
  3. package/dist/index.js +8 -1
  4. package/dist/llm/LLMService.d.ts +29 -2
  5. package/dist/llm/LLMService.js +67 -36
  6. package/dist/llm/clients/LlamaCppClientAdapter.d.ts +116 -0
  7. package/dist/llm/clients/LlamaCppClientAdapter.js +289 -0
  8. package/dist/llm/clients/LlamaCppServerClient.d.ts +161 -0
  9. package/dist/llm/clients/LlamaCppServerClient.js +192 -0
  10. package/dist/llm/config.d.ts +12 -0
  11. package/dist/llm/config.js +81 -4
  12. package/dist/llm/services/ModelResolver.js +13 -13
  13. package/dist/llm/services/SettingsManager.js +17 -11
  14. package/dist/llm/types.d.ts +87 -22
  15. package/dist/prompting/parser.d.ts +2 -2
  16. package/dist/prompting/parser.js +2 -2
  17. package/dist/providers/fromEnvironment.d.ts +4 -0
  18. package/dist/providers/fromEnvironment.js +8 -0
  19. package/package.json +1 -1
  20. package/dist/llm/LLMService.createMessages.test.d.ts +0 -4
  21. package/dist/llm/LLMService.createMessages.test.js +0 -364
  22. package/dist/llm/LLMService.original.d.ts +0 -147
  23. package/dist/llm/LLMService.original.js +0 -656
  24. package/dist/llm/LLMService.prepareMessage.test.d.ts +0 -1
  25. package/dist/llm/LLMService.prepareMessage.test.js +0 -303
  26. package/dist/llm/LLMService.presets.test.d.ts +0 -1
  27. package/dist/llm/LLMService.presets.test.js +0 -210
  28. package/dist/llm/LLMService.sendMessage.preset.test.d.ts +0 -1
  29. package/dist/llm/LLMService.sendMessage.preset.test.js +0 -153
  30. package/dist/llm/LLMService.test.d.ts +0 -1
  31. package/dist/llm/LLMService.test.js +0 -620
  32. package/dist/llm/clients/AnthropicClientAdapter.test.d.ts +0 -1
  33. package/dist/llm/clients/AnthropicClientAdapter.test.js +0 -273
  34. package/dist/llm/clients/GeminiClientAdapter.test.d.ts +0 -1
  35. package/dist/llm/clients/GeminiClientAdapter.test.js +0 -405
  36. package/dist/llm/clients/MockClientAdapter.test.d.ts +0 -1
  37. package/dist/llm/clients/MockClientAdapter.test.js +0 -250
  38. package/dist/llm/clients/OpenAIClientAdapter.test.d.ts +0 -1
  39. package/dist/llm/clients/OpenAIClientAdapter.test.js +0 -258
  40. package/dist/llm/clients/adapterErrorUtils.test.d.ts +0 -1
  41. package/dist/llm/clients/adapterErrorUtils.test.js +0 -123
  42. package/dist/llm/config.test.d.ts +0 -1
  43. package/dist/llm/config.test.js +0 -176
  44. package/dist/llm/services/AdapterRegistry.test.d.ts +0 -1
  45. package/dist/llm/services/AdapterRegistry.test.js +0 -239
  46. package/dist/llm/services/ModelResolver.test.d.ts +0 -1
  47. package/dist/llm/services/ModelResolver.test.js +0 -158
  48. package/dist/llm/services/PresetManager.test.d.ts +0 -1
  49. package/dist/llm/services/PresetManager.test.js +0 -210
  50. package/dist/llm/services/RequestValidator.test.d.ts +0 -1
  51. package/dist/llm/services/RequestValidator.test.js +0 -159
  52. package/dist/llm/services/SettingsManager.test.d.ts +0 -1
  53. package/dist/llm/services/SettingsManager.test.js +0 -266
  54. package/dist/prompting/builder.d.ts +0 -38
  55. package/dist/prompting/builder.js +0 -63
  56. package/dist/prompting/builder.test.d.ts +0 -4
  57. package/dist/prompting/builder.test.js +0 -109
  58. package/dist/prompting/content.test.d.ts +0 -4
  59. package/dist/prompting/content.test.js +0 -212
  60. package/dist/prompting/parser.test.d.ts +0 -4
  61. package/dist/prompting/parser.test.js +0 -464
  62. package/dist/prompting/template.test.d.ts +0 -1
  63. package/dist/prompting/template.test.js +0 -250
  64. package/dist/providers/fromEnvironment.test.d.ts +0 -1
  65. 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 {};