genai-lite 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +241 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +27 -0
- package/dist/llm/LLMService.d.ts +86 -0
- package/dist/llm/LLMService.js +410 -0
- package/dist/llm/clients/AnthropicClientAdapter.d.ts +84 -0
- package/dist/llm/clients/AnthropicClientAdapter.js +281 -0
- package/dist/llm/clients/GeminiClientAdapter.d.ts +83 -0
- package/dist/llm/clients/GeminiClientAdapter.js +266 -0
- package/dist/llm/clients/MockClientAdapter.d.ts +69 -0
- package/dist/llm/clients/MockClientAdapter.js +284 -0
- package/dist/llm/clients/OpenAIClientAdapter.d.ts +69 -0
- package/dist/llm/clients/OpenAIClientAdapter.js +227 -0
- package/dist/llm/clients/adapterErrorUtils.d.ts +26 -0
- package/dist/llm/clients/adapterErrorUtils.js +107 -0
- package/dist/llm/clients/types.d.ts +65 -0
- package/dist/llm/clients/types.js +19 -0
- package/dist/llm/config.d.ts +90 -0
- package/dist/llm/config.js +508 -0
- package/dist/llm/types.d.ts +155 -0
- package/dist/llm/types.js +14 -0
- package/dist/providers/fromEnvironment.d.ts +8 -0
- package/dist/providers/fromEnvironment.js +14 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.js +2 -0
- package/package.json +38 -0
|
@@ -0,0 +1,410 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.LLMService = void 0;
|
|
6
|
+
const MockClientAdapter_1 = require("./clients/MockClientAdapter");
|
|
7
|
+
const config_1 = require("./config");
|
|
8
|
+
/**
|
|
9
|
+
* Main process service for LLM operations
|
|
10
|
+
*
|
|
11
|
+
* This service:
|
|
12
|
+
* - Manages LLM provider client adapters
|
|
13
|
+
* - Integrates with ApiKeyServiceMain for secure API key access
|
|
14
|
+
* - Validates requests and applies default settings
|
|
15
|
+
* - Routes requests to appropriate provider adapters
|
|
16
|
+
* - Handles errors and provides standardized responses
|
|
17
|
+
*/
|
|
18
|
+
class LLMService {
|
|
19
|
+
constructor(getApiKey) {
|
|
20
|
+
this.getApiKey = getApiKey;
|
|
21
|
+
this.clientAdapters = new Map();
|
|
22
|
+
this.mockClientAdapter = new MockClientAdapter_1.MockClientAdapter();
|
|
23
|
+
// Dynamically register client adapters based on configuration
|
|
24
|
+
let registeredCount = 0;
|
|
25
|
+
const successfullyRegisteredProviders = [];
|
|
26
|
+
for (const provider of config_1.SUPPORTED_PROVIDERS) {
|
|
27
|
+
const AdapterClass = config_1.ADAPTER_CONSTRUCTORS[provider.id];
|
|
28
|
+
if (AdapterClass) {
|
|
29
|
+
try {
|
|
30
|
+
const adapterConfig = config_1.ADAPTER_CONFIGS[provider.id];
|
|
31
|
+
const adapterInstance = new AdapterClass(adapterConfig);
|
|
32
|
+
this.registerClientAdapter(provider.id, adapterInstance);
|
|
33
|
+
registeredCount++;
|
|
34
|
+
successfullyRegisteredProviders.push(provider.id);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.error(`LLMService: Failed to instantiate adapter for provider '${provider.id}'. This provider will use the mock adapter. Error:`, error);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
console.warn(`LLMService: No adapter constructor found for supported provider '${provider.id}'. This provider will use the mock adapter as a fallback.`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (registeredCount > 0) {
|
|
45
|
+
console.log(`LLMService: Initialized with ${registeredCount} dynamically registered adapter(s) for: ${successfullyRegisteredProviders.join(", ")}.`);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
console.log(`LLMService: No real adapters were dynamically registered. All providers will use the mock adapter.`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Gets list of supported LLM providers
|
|
53
|
+
*
|
|
54
|
+
* @returns Promise resolving to array of provider information
|
|
55
|
+
*/
|
|
56
|
+
async getProviders() {
|
|
57
|
+
console.log("LLMService.getProviders called");
|
|
58
|
+
return [...config_1.SUPPORTED_PROVIDERS]; // Return a copy to prevent external modification
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Gets list of supported models for a specific provider
|
|
62
|
+
*
|
|
63
|
+
* @param providerId - The provider ID to get models for
|
|
64
|
+
* @returns Promise resolving to array of model information
|
|
65
|
+
*/
|
|
66
|
+
async getModels(providerId) {
|
|
67
|
+
console.log(`LLMService.getModels called for provider: ${providerId}`);
|
|
68
|
+
// Validate provider exists
|
|
69
|
+
if (!(0, config_1.isProviderSupported)(providerId)) {
|
|
70
|
+
console.warn(`Requested models for unsupported provider: ${providerId}`);
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
const models = (0, config_1.getModelsByProvider)(providerId);
|
|
74
|
+
console.log(`Found ${models.length} models for provider: ${providerId}`);
|
|
75
|
+
return [...models]; // Return a copy to prevent external modification
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Sends a chat message to an LLM provider
|
|
79
|
+
*
|
|
80
|
+
* @param request - The LLM chat request
|
|
81
|
+
* @returns Promise resolving to either success or failure response
|
|
82
|
+
*/
|
|
83
|
+
async sendMessage(request) {
|
|
84
|
+
console.log(`LLMService.sendMessage called for provider: ${request.providerId}, model: ${request.modelId}`);
|
|
85
|
+
try {
|
|
86
|
+
// Validate provider
|
|
87
|
+
if (!(0, config_1.isProviderSupported)(request.providerId)) {
|
|
88
|
+
console.warn(`Unsupported provider in sendMessage: ${request.providerId}`);
|
|
89
|
+
return {
|
|
90
|
+
provider: request.providerId,
|
|
91
|
+
model: request.modelId,
|
|
92
|
+
error: {
|
|
93
|
+
message: `Unsupported provider: ${request.providerId}. Supported providers: ${config_1.SUPPORTED_PROVIDERS.map((p) => p.id).join(", ")}`,
|
|
94
|
+
code: "UNSUPPORTED_PROVIDER",
|
|
95
|
+
type: "validation_error",
|
|
96
|
+
},
|
|
97
|
+
object: "error",
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
// Validate model
|
|
101
|
+
if (!(0, config_1.isModelSupported)(request.modelId, request.providerId)) {
|
|
102
|
+
const availableModels = (0, config_1.getModelsByProvider)(request.providerId).map((m) => m.id);
|
|
103
|
+
console.warn(`Unsupported model ${request.modelId} for provider ${request.providerId}. Available: ${availableModels.join(", ")}`);
|
|
104
|
+
return {
|
|
105
|
+
provider: request.providerId,
|
|
106
|
+
model: request.modelId,
|
|
107
|
+
error: {
|
|
108
|
+
message: `Unsupported model: ${request.modelId} for provider: ${request.providerId}. Available models: ${availableModels.join(", ")}`,
|
|
109
|
+
code: "UNSUPPORTED_MODEL",
|
|
110
|
+
type: "validation_error",
|
|
111
|
+
},
|
|
112
|
+
object: "error",
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// Get model info for additional validation or settings
|
|
116
|
+
const modelInfo = (0, config_1.getModelById)(request.modelId, request.providerId);
|
|
117
|
+
if (!modelInfo) {
|
|
118
|
+
// This shouldn't happen if validation above passed, but defensive programming
|
|
119
|
+
console.error(`Model info not found for validated model: ${request.modelId}`);
|
|
120
|
+
return {
|
|
121
|
+
provider: request.providerId,
|
|
122
|
+
model: request.modelId,
|
|
123
|
+
error: {
|
|
124
|
+
message: `Internal error: Model configuration not found for ${request.modelId}`,
|
|
125
|
+
code: "MODEL_CONFIG_ERROR",
|
|
126
|
+
type: "internal_error",
|
|
127
|
+
},
|
|
128
|
+
object: "error",
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
// Validate basic request structure
|
|
132
|
+
const structureValidationResult = this.validateRequestStructure(request);
|
|
133
|
+
if (structureValidationResult) {
|
|
134
|
+
return structureValidationResult;
|
|
135
|
+
}
|
|
136
|
+
// Validate settings if provided
|
|
137
|
+
if (request.settings) {
|
|
138
|
+
const settingsValidationErrors = (0, config_1.validateLLMSettings)(request.settings);
|
|
139
|
+
if (settingsValidationErrors.length > 0) {
|
|
140
|
+
return {
|
|
141
|
+
provider: request.providerId,
|
|
142
|
+
model: request.modelId,
|
|
143
|
+
error: {
|
|
144
|
+
message: `Invalid settings: ${settingsValidationErrors.join(", ")}`,
|
|
145
|
+
code: "INVALID_SETTINGS",
|
|
146
|
+
type: "validation_error",
|
|
147
|
+
},
|
|
148
|
+
object: "error",
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// Apply model-specific defaults and merge with user settings
|
|
153
|
+
const finalSettings = this.mergeSettingsForModel(request.modelId, request.providerId, request.settings);
|
|
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)(request.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 '${request.providerId}', model '${request.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 '${request.providerId}', model '${request.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 '${request.providerId}', model '${request.modelId}'.`);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
const internalRequest = {
|
|
187
|
+
...request,
|
|
188
|
+
settings: filteredSettings,
|
|
189
|
+
};
|
|
190
|
+
console.log(`Processing LLM request with (potentially filtered) settings:`, {
|
|
191
|
+
provider: request.providerId,
|
|
192
|
+
model: request.modelId,
|
|
193
|
+
settings: filteredSettings,
|
|
194
|
+
messageCount: request.messages.length,
|
|
195
|
+
});
|
|
196
|
+
console.log(`Processing LLM request: ${request.messages.length} messages, model: ${request.modelId}`);
|
|
197
|
+
// Get client adapter
|
|
198
|
+
const clientAdapter = this.getClientAdapter(request.providerId);
|
|
199
|
+
// Use ApiKeyProvider to get the API key and make the request
|
|
200
|
+
try {
|
|
201
|
+
const apiKey = await this.getApiKey(request.providerId);
|
|
202
|
+
if (!apiKey) {
|
|
203
|
+
return {
|
|
204
|
+
provider: request.providerId,
|
|
205
|
+
model: request.modelId,
|
|
206
|
+
error: {
|
|
207
|
+
message: `API key for provider '${request.providerId}' could not be retrieved. Ensure your ApiKeyProvider is configured correctly.`,
|
|
208
|
+
code: "API_KEY_ERROR",
|
|
209
|
+
type: "authentication_error",
|
|
210
|
+
},
|
|
211
|
+
object: "error",
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
console.log(`Making LLM request with ${clientAdapter.constructor.name} for provider: ${request.providerId}`);
|
|
215
|
+
const result = await clientAdapter.sendMessage(internalRequest, apiKey);
|
|
216
|
+
console.log(`LLM request completed successfully for model: ${request.modelId}`);
|
|
217
|
+
return result;
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
console.error("Error in LLMService.sendMessage:", error);
|
|
221
|
+
return {
|
|
222
|
+
provider: request.providerId,
|
|
223
|
+
model: request.modelId,
|
|
224
|
+
error: {
|
|
225
|
+
message: error instanceof Error
|
|
226
|
+
? error.message
|
|
227
|
+
: "An unknown error occurred during message sending.",
|
|
228
|
+
code: "PROVIDER_ERROR",
|
|
229
|
+
type: "server_error",
|
|
230
|
+
providerError: error,
|
|
231
|
+
},
|
|
232
|
+
object: "error",
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
console.error("Error in LLMService.sendMessage (outer):", error);
|
|
238
|
+
return {
|
|
239
|
+
provider: request.providerId,
|
|
240
|
+
model: request.modelId,
|
|
241
|
+
error: {
|
|
242
|
+
message: error instanceof Error
|
|
243
|
+
? error.message
|
|
244
|
+
: "An unknown error occurred.",
|
|
245
|
+
code: "UNEXPECTED_ERROR",
|
|
246
|
+
type: "server_error",
|
|
247
|
+
providerError: error,
|
|
248
|
+
},
|
|
249
|
+
object: "error",
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Validates basic LLM request structure
|
|
255
|
+
*
|
|
256
|
+
* @param request - The request to validate
|
|
257
|
+
* @returns LLMFailureResponse if validation fails, null if valid
|
|
258
|
+
*/
|
|
259
|
+
validateRequestStructure(request) {
|
|
260
|
+
// Basic request structure validation
|
|
261
|
+
if (!request.messages ||
|
|
262
|
+
!Array.isArray(request.messages) ||
|
|
263
|
+
request.messages.length === 0) {
|
|
264
|
+
return {
|
|
265
|
+
provider: request.providerId,
|
|
266
|
+
model: request.modelId,
|
|
267
|
+
error: {
|
|
268
|
+
message: "Request must contain at least one message",
|
|
269
|
+
code: "INVALID_REQUEST",
|
|
270
|
+
type: "validation_error",
|
|
271
|
+
},
|
|
272
|
+
object: "error",
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
// Validate message structure
|
|
276
|
+
for (let i = 0; i < request.messages.length; i++) {
|
|
277
|
+
const message = request.messages[i];
|
|
278
|
+
if (!message.role || !message.content) {
|
|
279
|
+
return {
|
|
280
|
+
provider: request.providerId,
|
|
281
|
+
model: request.modelId,
|
|
282
|
+
error: {
|
|
283
|
+
message: `Message at index ${i} must have both 'role' and 'content' properties`,
|
|
284
|
+
code: "INVALID_MESSAGE",
|
|
285
|
+
type: "validation_error",
|
|
286
|
+
},
|
|
287
|
+
object: "error",
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
if (!["user", "assistant", "system"].includes(message.role)) {
|
|
291
|
+
return {
|
|
292
|
+
provider: request.providerId,
|
|
293
|
+
model: request.modelId,
|
|
294
|
+
error: {
|
|
295
|
+
message: `Invalid message role '${message.role}' at index ${i}. Must be 'user', 'assistant', or 'system'`,
|
|
296
|
+
code: "INVALID_MESSAGE_ROLE",
|
|
297
|
+
type: "validation_error",
|
|
298
|
+
},
|
|
299
|
+
object: "error",
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return null; // Request is valid
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Merges request settings with model-specific and global defaults
|
|
307
|
+
*
|
|
308
|
+
* @param modelId - The model ID to get defaults for
|
|
309
|
+
* @param providerId - The provider ID to get defaults for
|
|
310
|
+
* @param requestSettings - Settings from the request
|
|
311
|
+
* @returns Complete settings object with all required fields
|
|
312
|
+
*/
|
|
313
|
+
mergeSettingsForModel(modelId, providerId, requestSettings) {
|
|
314
|
+
// Get model-specific defaults
|
|
315
|
+
const modelDefaults = (0, config_1.getDefaultSettingsForModel)(modelId, providerId);
|
|
316
|
+
// Merge with user-provided settings (user settings take precedence)
|
|
317
|
+
const mergedSettings = {
|
|
318
|
+
temperature: requestSettings?.temperature ?? modelDefaults.temperature,
|
|
319
|
+
maxTokens: requestSettings?.maxTokens ?? modelDefaults.maxTokens,
|
|
320
|
+
topP: requestSettings?.topP ?? modelDefaults.topP,
|
|
321
|
+
stopSequences: requestSettings?.stopSequences ?? modelDefaults.stopSequences,
|
|
322
|
+
frequencyPenalty: requestSettings?.frequencyPenalty ?? modelDefaults.frequencyPenalty,
|
|
323
|
+
presencePenalty: requestSettings?.presencePenalty ?? modelDefaults.presencePenalty,
|
|
324
|
+
user: requestSettings?.user ?? modelDefaults.user,
|
|
325
|
+
supportsSystemMessage: requestSettings?.supportsSystemMessage ??
|
|
326
|
+
modelDefaults.supportsSystemMessage,
|
|
327
|
+
geminiSafetySettings: requestSettings?.geminiSafetySettings ??
|
|
328
|
+
modelDefaults.geminiSafetySettings,
|
|
329
|
+
};
|
|
330
|
+
// Log the final settings for debugging
|
|
331
|
+
console.log(`Merged settings for ${providerId}/${modelId}:`, {
|
|
332
|
+
temperature: mergedSettings.temperature,
|
|
333
|
+
maxTokens: mergedSettings.maxTokens,
|
|
334
|
+
topP: mergedSettings.topP,
|
|
335
|
+
hasStopSequences: mergedSettings.stopSequences.length > 0,
|
|
336
|
+
frequencyPenalty: mergedSettings.frequencyPenalty,
|
|
337
|
+
presencePenalty: mergedSettings.presencePenalty,
|
|
338
|
+
hasUser: !!mergedSettings.user,
|
|
339
|
+
geminiSafetySettingsCount: mergedSettings.geminiSafetySettings.length,
|
|
340
|
+
});
|
|
341
|
+
return mergedSettings;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Gets the appropriate client adapter for a provider
|
|
345
|
+
*
|
|
346
|
+
* @param providerId - The provider ID
|
|
347
|
+
* @returns The client adapter to use
|
|
348
|
+
*/
|
|
349
|
+
getClientAdapter(providerId) {
|
|
350
|
+
// Check for registered real adapters first
|
|
351
|
+
const registeredAdapter = this.clientAdapters.get(providerId);
|
|
352
|
+
if (registeredAdapter) {
|
|
353
|
+
console.log(`Using registered adapter for provider: ${providerId}`);
|
|
354
|
+
return registeredAdapter;
|
|
355
|
+
}
|
|
356
|
+
// Fall back to mock adapter for unsupported providers
|
|
357
|
+
console.log(`No real adapter found for ${providerId}, using mock adapter`);
|
|
358
|
+
return this.mockClientAdapter;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Registers a client adapter for a specific provider
|
|
362
|
+
*
|
|
363
|
+
* @param providerId - The provider ID
|
|
364
|
+
* @param adapter - The client adapter implementation
|
|
365
|
+
*/
|
|
366
|
+
registerClientAdapter(providerId, adapter) {
|
|
367
|
+
this.clientAdapters.set(providerId, adapter);
|
|
368
|
+
console.log(`Registered client adapter for provider: ${providerId}`);
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Gets information about registered adapters
|
|
372
|
+
*
|
|
373
|
+
* @returns Map of provider IDs to adapter info
|
|
374
|
+
*/
|
|
375
|
+
getRegisteredAdapters() {
|
|
376
|
+
const adapterInfo = new Map();
|
|
377
|
+
for (const [providerId, adapter] of this.clientAdapters.entries()) {
|
|
378
|
+
adapterInfo.set(providerId, {
|
|
379
|
+
providerId,
|
|
380
|
+
hasAdapter: true,
|
|
381
|
+
adapterInfo: adapter.getAdapterInfo?.() || { name: "Unknown Adapter" },
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
return adapterInfo;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Gets a summary of available providers and their adapter status
|
|
388
|
+
*
|
|
389
|
+
* @returns Summary of provider availability
|
|
390
|
+
*/
|
|
391
|
+
getProviderSummary() {
|
|
392
|
+
const availableProviders = [];
|
|
393
|
+
const unavailableProviders = [];
|
|
394
|
+
for (const provider of config_1.SUPPORTED_PROVIDERS) {
|
|
395
|
+
if (this.clientAdapters.has(provider.id)) {
|
|
396
|
+
availableProviders.push(provider.id);
|
|
397
|
+
}
|
|
398
|
+
else {
|
|
399
|
+
unavailableProviders.push(provider.id);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
return {
|
|
403
|
+
totalProviders: config_1.SUPPORTED_PROVIDERS.length,
|
|
404
|
+
providersWithAdapters: availableProviders.length,
|
|
405
|
+
availableProviders,
|
|
406
|
+
unavailableProviders,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
exports.LLMService = LLMService;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { LLMResponse, LLMFailureResponse } from "../types";
|
|
2
|
+
import type { ILLMClientAdapter, InternalLLMChatRequest } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Client adapter for Anthropic API integration
|
|
5
|
+
*
|
|
6
|
+
* This adapter:
|
|
7
|
+
* - Formats requests according to Anthropic's messages API requirements
|
|
8
|
+
* - Handles Claude-specific system message positioning and formatting
|
|
9
|
+
* - Maps Anthropic responses to standardized LLMResponse format
|
|
10
|
+
* - Converts Anthropic errors to standardized LLMFailureResponse format
|
|
11
|
+
* - Manages Claude-specific settings and constraints
|
|
12
|
+
*/
|
|
13
|
+
export declare class AnthropicClientAdapter implements ILLMClientAdapter {
|
|
14
|
+
private baseURL?;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a new Anthropic client adapter
|
|
17
|
+
*
|
|
18
|
+
* @param config Optional configuration for the adapter
|
|
19
|
+
* @param config.baseURL Custom base URL for Anthropic-compatible APIs
|
|
20
|
+
*/
|
|
21
|
+
constructor(config?: {
|
|
22
|
+
baseURL?: string;
|
|
23
|
+
});
|
|
24
|
+
/**
|
|
25
|
+
* Sends a chat message to Anthropic's API
|
|
26
|
+
*
|
|
27
|
+
* @param request - The internal LLM request with applied settings
|
|
28
|
+
* @param apiKey - The decrypted Anthropic API key
|
|
29
|
+
* @returns Promise resolving to success or failure response
|
|
30
|
+
*/
|
|
31
|
+
sendMessage(request: InternalLLMChatRequest, apiKey: string): Promise<LLMResponse | LLMFailureResponse>;
|
|
32
|
+
/**
|
|
33
|
+
* Validates Anthropic API key format
|
|
34
|
+
*
|
|
35
|
+
* @param apiKey - The API key to validate
|
|
36
|
+
* @returns True if the key format appears valid
|
|
37
|
+
*/
|
|
38
|
+
validateApiKey(apiKey: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Gets adapter information
|
|
41
|
+
*/
|
|
42
|
+
getAdapterInfo(): {
|
|
43
|
+
providerId: "anthropic";
|
|
44
|
+
name: string;
|
|
45
|
+
version: string;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Formats messages for Anthropic API with proper system message handling
|
|
49
|
+
*
|
|
50
|
+
* @param request - The internal LLM request
|
|
51
|
+
* @returns Formatted messages and system message for Anthropic
|
|
52
|
+
*/
|
|
53
|
+
private formatMessagesForAnthropic;
|
|
54
|
+
/**
|
|
55
|
+
* Ensures messages alternate between user and assistant roles as required by Anthropic
|
|
56
|
+
*
|
|
57
|
+
* @param messages - Original messages array
|
|
58
|
+
* @returns Cleaned messages with proper alternating pattern
|
|
59
|
+
*/
|
|
60
|
+
private ensureAlternatingRoles;
|
|
61
|
+
/**
|
|
62
|
+
* Creates a standardized success response from Anthropic's response
|
|
63
|
+
*
|
|
64
|
+
* @param completion - Raw Anthropic completion response
|
|
65
|
+
* @param request - Original request for context
|
|
66
|
+
* @returns Standardized LLM response
|
|
67
|
+
*/
|
|
68
|
+
private createSuccessResponse;
|
|
69
|
+
/**
|
|
70
|
+
* Maps Anthropic stop reasons to standardized format
|
|
71
|
+
*
|
|
72
|
+
* @param anthropicReason - The stop reason from Anthropic
|
|
73
|
+
* @returns Standardized finish reason
|
|
74
|
+
*/
|
|
75
|
+
private mapAnthropicStopReason;
|
|
76
|
+
/**
|
|
77
|
+
* Creates a standardized error response from Anthropic errors
|
|
78
|
+
*
|
|
79
|
+
* @param error - The error from Anthropic API
|
|
80
|
+
* @param request - Original request for context
|
|
81
|
+
* @returns Standardized LLM failure response
|
|
82
|
+
*/
|
|
83
|
+
private createErrorResponse;
|
|
84
|
+
}
|