genai-lite 0.2.0 → 0.3.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/README.md +508 -30
- package/dist/config/presets.json +121 -17
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -3
- package/dist/llm/LLMService.createMessages.test.d.ts +4 -0
- package/dist/llm/LLMService.createMessages.test.js +364 -0
- package/dist/llm/LLMService.d.ts +49 -47
- package/dist/llm/LLMService.js +208 -303
- package/dist/llm/LLMService.original.d.ts +147 -0
- package/dist/llm/LLMService.original.js +656 -0
- package/dist/llm/LLMService.prepareMessage.test.d.ts +1 -0
- package/dist/llm/LLMService.prepareMessage.test.js +303 -0
- package/dist/llm/LLMService.sendMessage.preset.test.d.ts +1 -0
- package/dist/llm/LLMService.sendMessage.preset.test.js +153 -0
- package/dist/llm/LLMService.test.js +275 -0
- package/dist/llm/clients/AnthropicClientAdapter.js +64 -10
- package/dist/llm/clients/AnthropicClientAdapter.test.js +11 -1
- package/dist/llm/clients/GeminiClientAdapter.js +70 -11
- package/dist/llm/clients/GeminiClientAdapter.test.js +125 -1
- package/dist/llm/clients/MockClientAdapter.js +9 -3
- package/dist/llm/clients/MockClientAdapter.test.js +11 -1
- package/dist/llm/clients/OpenAIClientAdapter.js +26 -10
- package/dist/llm/clients/OpenAIClientAdapter.test.js +11 -1
- package/dist/llm/config.js +117 -2
- package/dist/llm/config.test.js +17 -0
- package/dist/llm/services/AdapterRegistry.d.ts +59 -0
- package/dist/llm/services/AdapterRegistry.js +113 -0
- package/dist/llm/services/AdapterRegistry.test.d.ts +1 -0
- package/dist/llm/services/AdapterRegistry.test.js +239 -0
- package/dist/llm/services/ModelResolver.d.ts +35 -0
- package/dist/llm/services/ModelResolver.js +116 -0
- package/dist/llm/services/ModelResolver.test.d.ts +1 -0
- package/dist/llm/services/ModelResolver.test.js +158 -0
- package/dist/llm/services/PresetManager.d.ts +27 -0
- package/dist/llm/services/PresetManager.js +50 -0
- package/dist/llm/services/PresetManager.test.d.ts +1 -0
- package/dist/llm/services/PresetManager.test.js +210 -0
- package/dist/llm/services/RequestValidator.d.ts +31 -0
- package/dist/llm/services/RequestValidator.js +122 -0
- package/dist/llm/services/RequestValidator.test.d.ts +1 -0
- package/dist/llm/services/RequestValidator.test.js +159 -0
- package/dist/llm/services/SettingsManager.d.ts +32 -0
- package/dist/llm/services/SettingsManager.js +223 -0
- package/dist/llm/services/SettingsManager.test.d.ts +1 -0
- package/dist/llm/services/SettingsManager.test.js +266 -0
- package/dist/llm/types.d.ts +107 -0
- package/dist/prompting/builder.d.ts +4 -0
- package/dist/prompting/builder.js +12 -61
- package/dist/prompting/content.js +3 -9
- package/dist/prompting/index.d.ts +2 -3
- package/dist/prompting/index.js +4 -5
- package/dist/prompting/parser.d.ts +80 -0
- package/dist/prompting/parser.js +133 -0
- package/dist/prompting/parser.test.js +348 -0
- package/dist/prompting/template.d.ts +8 -0
- package/dist/prompting/template.js +89 -6
- package/dist/prompting/template.test.js +116 -0
- package/package.json +3 -2
- package/src/config/presets.json +122 -17
|
@@ -31,7 +31,8 @@ class MockClientAdapter {
|
|
|
31
31
|
try {
|
|
32
32
|
// Check for special test patterns in the last user message
|
|
33
33
|
const lastMessage = request.messages[request.messages.length - 1];
|
|
34
|
-
const
|
|
34
|
+
const originalContent = lastMessage?.content || "";
|
|
35
|
+
const content = originalContent.toLowerCase();
|
|
35
36
|
// Simulate various error conditions based on message content
|
|
36
37
|
if (content.includes("error_invalid_key")) {
|
|
37
38
|
return this.createErrorResponse("Invalid API key provided", types_1.ADAPTER_ERROR_CODES.INVALID_API_KEY, 401, request);
|
|
@@ -58,7 +59,7 @@ class MockClientAdapter {
|
|
|
58
59
|
return this.createErrorResponse("Generic provider error", types_1.ADAPTER_ERROR_CODES.PROVIDER_ERROR, 500, request);
|
|
59
60
|
}
|
|
60
61
|
// Generate successful mock response
|
|
61
|
-
return this.createSuccessResponse(request, content);
|
|
62
|
+
return this.createSuccessResponse(request, content, originalContent);
|
|
62
63
|
}
|
|
63
64
|
catch (error) {
|
|
64
65
|
return this.createErrorResponse(`Mock adapter error: ${error instanceof Error ? error.message : "Unknown error"}`, types_1.ADAPTER_ERROR_CODES.UNKNOWN_ERROR, 500, request);
|
|
@@ -84,7 +85,7 @@ class MockClientAdapter {
|
|
|
84
85
|
/**
|
|
85
86
|
* Creates a successful mock response
|
|
86
87
|
*/
|
|
87
|
-
createSuccessResponse(request, userContent) {
|
|
88
|
+
createSuccessResponse(request, userContent, originalContent) {
|
|
88
89
|
// Generate response content based on user input and settings
|
|
89
90
|
let responseContent;
|
|
90
91
|
// Check for settings-based test patterns
|
|
@@ -94,6 +95,11 @@ class MockClientAdapter {
|
|
|
94
95
|
else if (userContent.includes("test_settings")) {
|
|
95
96
|
responseContent = this.generateSettingsTestResponse(request.settings);
|
|
96
97
|
}
|
|
98
|
+
else if (userContent.includes("test_thinking:")) {
|
|
99
|
+
// Extract content after "test_thinking:" for testing thinking extraction
|
|
100
|
+
const startIndex = originalContent.indexOf("test_thinking:") + "test_thinking:".length;
|
|
101
|
+
responseContent = originalContent.substring(startIndex).trim();
|
|
102
|
+
}
|
|
97
103
|
else if (userContent.includes("hello") || userContent.includes("hi")) {
|
|
98
104
|
responseContent =
|
|
99
105
|
"Hello! I'm a mock LLM assistant. How can I help you today?";
|
|
@@ -20,7 +20,17 @@ describe('MockClientAdapter', () => {
|
|
|
20
20
|
stopSequences: [],
|
|
21
21
|
user: 'test-user',
|
|
22
22
|
geminiSafetySettings: [],
|
|
23
|
-
supportsSystemMessage: true
|
|
23
|
+
supportsSystemMessage: true,
|
|
24
|
+
reasoning: {
|
|
25
|
+
enabled: false,
|
|
26
|
+
effort: undefined,
|
|
27
|
+
maxTokens: undefined,
|
|
28
|
+
exclude: false
|
|
29
|
+
},
|
|
30
|
+
thinkingExtraction: {
|
|
31
|
+
enabled: true,
|
|
32
|
+
tag: 'thinking'
|
|
33
|
+
}
|
|
24
34
|
}
|
|
25
35
|
};
|
|
26
36
|
});
|
|
@@ -64,6 +64,18 @@ class OpenAIClientAdapter {
|
|
|
64
64
|
user: request.settings.user,
|
|
65
65
|
}),
|
|
66
66
|
};
|
|
67
|
+
// Handle reasoning configuration for OpenAI models (o-series)
|
|
68
|
+
if (request.settings.reasoning && !request.settings.reasoning.exclude) {
|
|
69
|
+
const reasoning = request.settings.reasoning;
|
|
70
|
+
// OpenAI uses reasoning_effort for o-series models
|
|
71
|
+
if (reasoning.effort) {
|
|
72
|
+
completionParams.reasoning_effort = reasoning.effort;
|
|
73
|
+
}
|
|
74
|
+
else if (reasoning.enabled !== false) {
|
|
75
|
+
// Default to medium effort if reasoning is enabled
|
|
76
|
+
completionParams.reasoning_effort = 'medium';
|
|
77
|
+
}
|
|
78
|
+
}
|
|
67
79
|
console.log(`OpenAI API parameters:`, {
|
|
68
80
|
model: completionParams.model,
|
|
69
81
|
temperature: completionParams.temperature,
|
|
@@ -163,21 +175,25 @@ class OpenAIClientAdapter {
|
|
|
163
175
|
if (!choice || !choice.message) {
|
|
164
176
|
throw new Error("Invalid completion structure from OpenAI API");
|
|
165
177
|
}
|
|
178
|
+
const responseChoice = {
|
|
179
|
+
message: {
|
|
180
|
+
role: choice.message.role,
|
|
181
|
+
content: choice.message.content || "",
|
|
182
|
+
},
|
|
183
|
+
finish_reason: choice.finish_reason,
|
|
184
|
+
index: choice.index,
|
|
185
|
+
};
|
|
186
|
+
// Check for reasoning content if OpenAI starts returning it
|
|
187
|
+
// (Currently o-series models don't return reasoning tokens)
|
|
188
|
+
if (choice.reasoning && request.settings.reasoning && !request.settings.reasoning.exclude) {
|
|
189
|
+
responseChoice.reasoning = choice.reasoning;
|
|
190
|
+
}
|
|
166
191
|
return {
|
|
167
192
|
id: completion.id,
|
|
168
193
|
provider: request.providerId,
|
|
169
194
|
model: completion.model || request.modelId,
|
|
170
195
|
created: completion.created,
|
|
171
|
-
choices: [
|
|
172
|
-
{
|
|
173
|
-
message: {
|
|
174
|
-
role: choice.message.role,
|
|
175
|
-
content: choice.message.content || "",
|
|
176
|
-
},
|
|
177
|
-
finish_reason: choice.finish_reason,
|
|
178
|
-
index: choice.index,
|
|
179
|
-
},
|
|
180
|
-
],
|
|
196
|
+
choices: [responseChoice],
|
|
181
197
|
usage: completion.usage
|
|
182
198
|
? {
|
|
183
199
|
prompt_tokens: completion.usage.prompt_tokens,
|
|
@@ -38,7 +38,17 @@ describe('OpenAIClientAdapter', () => {
|
|
|
38
38
|
stopSequences: [],
|
|
39
39
|
user: 'test-user',
|
|
40
40
|
geminiSafetySettings: [],
|
|
41
|
-
supportsSystemMessage: true
|
|
41
|
+
supportsSystemMessage: true,
|
|
42
|
+
reasoning: {
|
|
43
|
+
enabled: false,
|
|
44
|
+
effort: undefined,
|
|
45
|
+
maxTokens: undefined,
|
|
46
|
+
exclude: false
|
|
47
|
+
},
|
|
48
|
+
thinkingExtraction: {
|
|
49
|
+
enabled: true,
|
|
50
|
+
tag: 'thinking'
|
|
51
|
+
}
|
|
42
52
|
}
|
|
43
53
|
};
|
|
44
54
|
});
|
package/dist/llm/config.js
CHANGED
|
@@ -57,6 +57,17 @@ exports.DEFAULT_LLM_SETTINGS = {
|
|
|
57
57
|
{ category: "HARM_CATEGORY_DANGEROUS_CONTENT", threshold: "BLOCK_NONE" },
|
|
58
58
|
{ category: "HARM_CATEGORY_HARASSMENT", threshold: "BLOCK_NONE" },
|
|
59
59
|
],
|
|
60
|
+
reasoning: {
|
|
61
|
+
enabled: false,
|
|
62
|
+
effort: undefined,
|
|
63
|
+
maxTokens: undefined,
|
|
64
|
+
exclude: false,
|
|
65
|
+
},
|
|
66
|
+
thinkingExtraction: {
|
|
67
|
+
enabled: false, // Now requires explicit opt-in, works with onMissing: 'auto'
|
|
68
|
+
tag: 'thinking',
|
|
69
|
+
onMissing: 'auto' // Smart enforcement based on native reasoning status
|
|
70
|
+
},
|
|
60
71
|
};
|
|
61
72
|
/**
|
|
62
73
|
* Per-provider default setting overrides
|
|
@@ -126,6 +137,16 @@ exports.SUPPORTED_MODELS = [
|
|
|
126
137
|
supportsPromptCache: true,
|
|
127
138
|
cacheWritesPrice: 3.75,
|
|
128
139
|
cacheReadsPrice: 0.3,
|
|
140
|
+
reasoning: {
|
|
141
|
+
supported: true,
|
|
142
|
+
enabledByDefault: false,
|
|
143
|
+
canDisable: true,
|
|
144
|
+
minBudget: 1024,
|
|
145
|
+
maxBudget: 32000,
|
|
146
|
+
defaultBudget: 10000,
|
|
147
|
+
outputType: 'summary',
|
|
148
|
+
requiresStreamingAbove: 21333,
|
|
149
|
+
},
|
|
129
150
|
},
|
|
130
151
|
{
|
|
131
152
|
id: "claude-opus-4-20250514",
|
|
@@ -140,6 +161,16 @@ exports.SUPPORTED_MODELS = [
|
|
|
140
161
|
supportsPromptCache: true,
|
|
141
162
|
cacheWritesPrice: 18.75,
|
|
142
163
|
cacheReadsPrice: 1.5,
|
|
164
|
+
reasoning: {
|
|
165
|
+
supported: true,
|
|
166
|
+
enabledByDefault: false,
|
|
167
|
+
canDisable: true,
|
|
168
|
+
minBudget: 1024,
|
|
169
|
+
maxBudget: 32000,
|
|
170
|
+
defaultBudget: 10000,
|
|
171
|
+
outputType: 'summary',
|
|
172
|
+
requiresStreamingAbove: 21333,
|
|
173
|
+
},
|
|
143
174
|
},
|
|
144
175
|
{
|
|
145
176
|
id: "claude-3-7-sonnet-20250219",
|
|
@@ -154,6 +185,16 @@ exports.SUPPORTED_MODELS = [
|
|
|
154
185
|
supportsPromptCache: true,
|
|
155
186
|
cacheWritesPrice: 3.75,
|
|
156
187
|
cacheReadsPrice: 0.3,
|
|
188
|
+
reasoning: {
|
|
189
|
+
supported: true,
|
|
190
|
+
enabledByDefault: false,
|
|
191
|
+
canDisable: true,
|
|
192
|
+
minBudget: 1024,
|
|
193
|
+
maxBudget: 32000,
|
|
194
|
+
defaultBudget: 10000,
|
|
195
|
+
outputType: 'full',
|
|
196
|
+
requiresStreamingAbove: 21333,
|
|
197
|
+
},
|
|
157
198
|
},
|
|
158
199
|
{
|
|
159
200
|
id: "claude-3-5-sonnet-20241022",
|
|
@@ -196,6 +237,19 @@ exports.SUPPORTED_MODELS = [
|
|
|
196
237
|
supportsImages: true,
|
|
197
238
|
supportsPromptCache: true,
|
|
198
239
|
cacheReadsPrice: 0.31,
|
|
240
|
+
reasoning: {
|
|
241
|
+
supported: true,
|
|
242
|
+
enabledByDefault: true,
|
|
243
|
+
canDisable: false,
|
|
244
|
+
minBudget: 1024,
|
|
245
|
+
maxBudget: 65536,
|
|
246
|
+
defaultBudget: -1,
|
|
247
|
+
dynamicBudget: {
|
|
248
|
+
value: -1,
|
|
249
|
+
description: "Let model decide based on query complexity",
|
|
250
|
+
},
|
|
251
|
+
outputType: 'summary',
|
|
252
|
+
},
|
|
199
253
|
},
|
|
200
254
|
{
|
|
201
255
|
id: "gemini-2.5-flash",
|
|
@@ -208,9 +262,18 @@ exports.SUPPORTED_MODELS = [
|
|
|
208
262
|
maxTokens: 65536,
|
|
209
263
|
supportsImages: true,
|
|
210
264
|
supportsPromptCache: true,
|
|
211
|
-
|
|
265
|
+
reasoning: {
|
|
266
|
+
supported: true,
|
|
267
|
+
enabledByDefault: true,
|
|
268
|
+
canDisable: true,
|
|
269
|
+
minBudget: 1024,
|
|
212
270
|
maxBudget: 24576,
|
|
213
|
-
|
|
271
|
+
defaultBudget: -1,
|
|
272
|
+
dynamicBudget: {
|
|
273
|
+
value: -1,
|
|
274
|
+
description: "Let model decide based on query complexity",
|
|
275
|
+
},
|
|
276
|
+
outputType: 'summary',
|
|
214
277
|
},
|
|
215
278
|
},
|
|
216
279
|
{
|
|
@@ -224,6 +287,19 @@ exports.SUPPORTED_MODELS = [
|
|
|
224
287
|
maxTokens: 64000,
|
|
225
288
|
supportsImages: true,
|
|
226
289
|
supportsPromptCache: true,
|
|
290
|
+
reasoning: {
|
|
291
|
+
supported: true,
|
|
292
|
+
enabledByDefault: false,
|
|
293
|
+
canDisable: true,
|
|
294
|
+
minBudget: 512,
|
|
295
|
+
maxBudget: 24576,
|
|
296
|
+
defaultBudget: -1,
|
|
297
|
+
dynamicBudget: {
|
|
298
|
+
value: -1,
|
|
299
|
+
description: "Let model decide based on query complexity",
|
|
300
|
+
},
|
|
301
|
+
outputType: 'summary',
|
|
302
|
+
},
|
|
227
303
|
},
|
|
228
304
|
{
|
|
229
305
|
id: "gemini-2.0-flash",
|
|
@@ -265,6 +341,12 @@ exports.SUPPORTED_MODELS = [
|
|
|
265
341
|
supportsPromptCache: true,
|
|
266
342
|
cacheReadsPrice: 0.275,
|
|
267
343
|
unsupportedParameters: ["topP"],
|
|
344
|
+
reasoning: {
|
|
345
|
+
supported: true,
|
|
346
|
+
enabledByDefault: true,
|
|
347
|
+
canDisable: false,
|
|
348
|
+
outputType: 'none',
|
|
349
|
+
},
|
|
268
350
|
},
|
|
269
351
|
{
|
|
270
352
|
id: "gpt-4.1",
|
|
@@ -401,6 +483,16 @@ function getDefaultSettingsForModel(modelId, providerId) {
|
|
|
401
483
|
if (modelInfo && modelInfo.maxTokens !== undefined) {
|
|
402
484
|
mergedSettings.maxTokens = modelInfo.maxTokens;
|
|
403
485
|
}
|
|
486
|
+
// Handle reasoning settings based on model capabilities
|
|
487
|
+
if (modelInfo?.reasoning?.supported) {
|
|
488
|
+
// If the model has reasoning enabled by default, update the settings
|
|
489
|
+
if (modelInfo.reasoning.enabledByDefault) {
|
|
490
|
+
mergedSettings.reasoning = {
|
|
491
|
+
...mergedSettings.reasoning,
|
|
492
|
+
enabled: true,
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
}
|
|
404
496
|
// Filter out undefined values and ensure required fields
|
|
405
497
|
return Object.fromEntries(Object.entries(mergedSettings).filter(([_, value]) => value !== undefined));
|
|
406
498
|
}
|
|
@@ -504,5 +596,28 @@ function validateLLMSettings(settings) {
|
|
|
504
596
|
}
|
|
505
597
|
}
|
|
506
598
|
}
|
|
599
|
+
if (settings.reasoning !== undefined) {
|
|
600
|
+
if (typeof settings.reasoning !== "object" || settings.reasoning === null) {
|
|
601
|
+
errors.push("reasoning must be an object");
|
|
602
|
+
}
|
|
603
|
+
else {
|
|
604
|
+
if (settings.reasoning.enabled !== undefined && typeof settings.reasoning.enabled !== "boolean") {
|
|
605
|
+
errors.push("reasoning.enabled must be a boolean");
|
|
606
|
+
}
|
|
607
|
+
if (settings.reasoning.effort !== undefined) {
|
|
608
|
+
if (!["high", "medium", "low"].includes(settings.reasoning.effort)) {
|
|
609
|
+
errors.push("reasoning.effort must be 'high', 'medium', or 'low'");
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
if (settings.reasoning.maxTokens !== undefined) {
|
|
613
|
+
if (!Number.isInteger(settings.reasoning.maxTokens) || settings.reasoning.maxTokens < 0) {
|
|
614
|
+
errors.push("reasoning.maxTokens must be a non-negative integer");
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
if (settings.reasoning.exclude !== undefined && typeof settings.reasoning.exclude !== "boolean") {
|
|
618
|
+
errors.push("reasoning.exclude must be a boolean");
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
507
622
|
return errors;
|
|
508
623
|
}
|
package/dist/llm/config.test.js
CHANGED
|
@@ -143,6 +143,23 @@ describe('LLM Config', () => {
|
|
|
143
143
|
};
|
|
144
144
|
expect((0, config_1.validateLLMSettings)(validGeminiSettings)).toEqual([]);
|
|
145
145
|
});
|
|
146
|
+
it('should validate reasoning settings', () => {
|
|
147
|
+
// Invalid reasoning object
|
|
148
|
+
expect((0, config_1.validateLLMSettings)({ reasoning: 'invalid' })).toContain('reasoning must be an object');
|
|
149
|
+
// Invalid enabled value
|
|
150
|
+
expect((0, config_1.validateLLMSettings)({ reasoning: { enabled: 'yes' } })).toContain('reasoning.enabled must be a boolean');
|
|
151
|
+
// Invalid effort value
|
|
152
|
+
expect((0, config_1.validateLLMSettings)({ reasoning: { effort: 'maximum' } })).toContain("reasoning.effort must be 'high', 'medium', or 'low'");
|
|
153
|
+
expect((0, config_1.validateLLMSettings)({ reasoning: { effort: 'high' } })).toEqual([]);
|
|
154
|
+
// Invalid maxTokens value
|
|
155
|
+
expect((0, config_1.validateLLMSettings)({ reasoning: { maxTokens: -100 } })).toContain('reasoning.maxTokens must be a non-negative integer');
|
|
156
|
+
expect((0, config_1.validateLLMSettings)({ reasoning: { maxTokens: 1.5 } })).toContain('reasoning.maxTokens must be a non-negative integer');
|
|
157
|
+
expect((0, config_1.validateLLMSettings)({ reasoning: { maxTokens: 5000 } })).toEqual([]);
|
|
158
|
+
// Invalid exclude value
|
|
159
|
+
expect((0, config_1.validateLLMSettings)({ reasoning: { exclude: 'yes' } })).toContain('reasoning.exclude must be a boolean');
|
|
160
|
+
// Valid reasoning settings
|
|
161
|
+
expect((0, config_1.validateLLMSettings)({ reasoning: { enabled: true, effort: 'medium', maxTokens: 10000, exclude: false } })).toEqual([]);
|
|
162
|
+
});
|
|
146
163
|
it('should return multiple errors for multiple invalid fields', () => {
|
|
147
164
|
const invalidSettings = {
|
|
148
165
|
temperature: -1,
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { ApiProviderId } from "../types";
|
|
2
|
+
import type { ILLMClientAdapter } from "../clients/types";
|
|
3
|
+
/**
|
|
4
|
+
* Information about a registered adapter
|
|
5
|
+
*/
|
|
6
|
+
export interface AdapterInfo {
|
|
7
|
+
providerId: ApiProviderId;
|
|
8
|
+
hasAdapter: boolean;
|
|
9
|
+
adapterInfo: {
|
|
10
|
+
name: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Summary of provider availability
|
|
15
|
+
*/
|
|
16
|
+
export interface ProviderSummary {
|
|
17
|
+
totalProviders: number;
|
|
18
|
+
providersWithAdapters: number;
|
|
19
|
+
availableProviders: string[];
|
|
20
|
+
unavailableProviders: string[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Registry for managing LLM client adapters
|
|
24
|
+
*/
|
|
25
|
+
export declare class AdapterRegistry {
|
|
26
|
+
private clientAdapters;
|
|
27
|
+
private mockClientAdapter;
|
|
28
|
+
constructor();
|
|
29
|
+
/**
|
|
30
|
+
* Initializes adapters for all supported providers
|
|
31
|
+
*/
|
|
32
|
+
private initializeAdapters;
|
|
33
|
+
/**
|
|
34
|
+
* Registers a client adapter for a specific provider
|
|
35
|
+
*
|
|
36
|
+
* @param providerId - The provider ID
|
|
37
|
+
* @param adapter - The client adapter implementation
|
|
38
|
+
*/
|
|
39
|
+
registerAdapter(providerId: ApiProviderId, adapter: ILLMClientAdapter): void;
|
|
40
|
+
/**
|
|
41
|
+
* Gets the appropriate client adapter for a provider
|
|
42
|
+
*
|
|
43
|
+
* @param providerId - The provider ID
|
|
44
|
+
* @returns The client adapter to use
|
|
45
|
+
*/
|
|
46
|
+
getAdapter(providerId: ApiProviderId): ILLMClientAdapter;
|
|
47
|
+
/**
|
|
48
|
+
* Gets information about registered adapters
|
|
49
|
+
*
|
|
50
|
+
* @returns Map of provider IDs to adapter info
|
|
51
|
+
*/
|
|
52
|
+
getRegisteredAdapters(): Map<ApiProviderId, AdapterInfo>;
|
|
53
|
+
/**
|
|
54
|
+
* Gets a summary of available providers and their adapter status
|
|
55
|
+
*
|
|
56
|
+
* @returns Summary of provider availability
|
|
57
|
+
*/
|
|
58
|
+
getProviderSummary(): ProviderSummary;
|
|
59
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AdapterRegistry = void 0;
|
|
4
|
+
const MockClientAdapter_1 = require("../clients/MockClientAdapter");
|
|
5
|
+
const config_1 = require("../config");
|
|
6
|
+
/**
|
|
7
|
+
* Registry for managing LLM client adapters
|
|
8
|
+
*/
|
|
9
|
+
class AdapterRegistry {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.clientAdapters = new Map();
|
|
12
|
+
this.mockClientAdapter = new MockClientAdapter_1.MockClientAdapter();
|
|
13
|
+
this.initializeAdapters();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Initializes adapters for all supported providers
|
|
17
|
+
*/
|
|
18
|
+
initializeAdapters() {
|
|
19
|
+
let registeredCount = 0;
|
|
20
|
+
const successfullyRegisteredProviders = [];
|
|
21
|
+
for (const provider of config_1.SUPPORTED_PROVIDERS) {
|
|
22
|
+
const AdapterClass = config_1.ADAPTER_CONSTRUCTORS[provider.id];
|
|
23
|
+
if (AdapterClass) {
|
|
24
|
+
try {
|
|
25
|
+
const adapterConfig = config_1.ADAPTER_CONFIGS[provider.id];
|
|
26
|
+
const adapterInstance = new AdapterClass(adapterConfig);
|
|
27
|
+
this.registerAdapter(provider.id, adapterInstance);
|
|
28
|
+
registeredCount++;
|
|
29
|
+
successfullyRegisteredProviders.push(provider.id);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
console.error(`LLMService: Failed to instantiate adapter for provider '${provider.id}'. This provider will use the mock adapter. Error:`, error);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
console.warn(`LLMService: No adapter constructor found for supported provider '${provider.id}'. This provider will use the mock adapter as a fallback.`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (registeredCount > 0) {
|
|
40
|
+
console.log(`LLMService: Initialized with ${registeredCount} dynamically registered adapter(s) for: ${successfullyRegisteredProviders.join(", ")}.`);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
console.log(`LLMService: No real adapters were dynamically registered. All providers will use the mock adapter.`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Registers a client adapter for a specific provider
|
|
48
|
+
*
|
|
49
|
+
* @param providerId - The provider ID
|
|
50
|
+
* @param adapter - The client adapter implementation
|
|
51
|
+
*/
|
|
52
|
+
registerAdapter(providerId, adapter) {
|
|
53
|
+
this.clientAdapters.set(providerId, adapter);
|
|
54
|
+
console.log(`Registered client adapter for provider: ${providerId}`);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Gets the appropriate client adapter for a provider
|
|
58
|
+
*
|
|
59
|
+
* @param providerId - The provider ID
|
|
60
|
+
* @returns The client adapter to use
|
|
61
|
+
*/
|
|
62
|
+
getAdapter(providerId) {
|
|
63
|
+
// Check for registered real adapters first
|
|
64
|
+
const registeredAdapter = this.clientAdapters.get(providerId);
|
|
65
|
+
if (registeredAdapter) {
|
|
66
|
+
console.log(`Using registered adapter for provider: ${providerId}`);
|
|
67
|
+
return registeredAdapter;
|
|
68
|
+
}
|
|
69
|
+
// Fall back to mock adapter for unsupported providers
|
|
70
|
+
console.log(`No real adapter found for ${providerId}, using mock adapter`);
|
|
71
|
+
return this.mockClientAdapter;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Gets information about registered adapters
|
|
75
|
+
*
|
|
76
|
+
* @returns Map of provider IDs to adapter info
|
|
77
|
+
*/
|
|
78
|
+
getRegisteredAdapters() {
|
|
79
|
+
const adapterInfo = new Map();
|
|
80
|
+
for (const [providerId, adapter] of this.clientAdapters.entries()) {
|
|
81
|
+
adapterInfo.set(providerId, {
|
|
82
|
+
providerId,
|
|
83
|
+
hasAdapter: true,
|
|
84
|
+
adapterInfo: adapter.getAdapterInfo?.() || { name: "Unknown Adapter" },
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return adapterInfo;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Gets a summary of available providers and their adapter status
|
|
91
|
+
*
|
|
92
|
+
* @returns Summary of provider availability
|
|
93
|
+
*/
|
|
94
|
+
getProviderSummary() {
|
|
95
|
+
const availableProviders = [];
|
|
96
|
+
const unavailableProviders = [];
|
|
97
|
+
for (const provider of config_1.SUPPORTED_PROVIDERS) {
|
|
98
|
+
if (this.clientAdapters.has(provider.id)) {
|
|
99
|
+
availableProviders.push(provider.id);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
unavailableProviders.push(provider.id);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
totalProviders: config_1.SUPPORTED_PROVIDERS.length,
|
|
107
|
+
providersWithAdapters: availableProviders.length,
|
|
108
|
+
availableProviders,
|
|
109
|
+
unavailableProviders,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
exports.AdapterRegistry = AdapterRegistry;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|