genai-lite 0.8.2 → 0.9.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 -21
- package/README.md +210 -207
- package/dist/adapters/image/GenaiElectronImageAdapter.d.ts +1 -0
- package/dist/adapters/image/GenaiElectronImageAdapter.js +5 -5
- package/dist/adapters/image/OpenAIImageAdapter.d.ts +1 -0
- package/dist/adapters/image/OpenAIImageAdapter.js +4 -4
- package/dist/config/llm-presets.json +24 -0
- package/dist/image/ImageService.js +2 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +6 -1
- package/dist/llm/LLMService.d.ts +30 -1
- package/dist/llm/LLMService.js +43 -5
- package/dist/llm/clients/AnthropicClientAdapter.d.ts +6 -2
- package/dist/llm/clients/AnthropicClientAdapter.js +26 -11
- package/dist/llm/clients/GeminiClientAdapter.d.ts +6 -2
- package/dist/llm/clients/GeminiClientAdapter.js +21 -9
- package/dist/llm/clients/LlamaCppClientAdapter.d.ts +8 -4
- package/dist/llm/clients/LlamaCppClientAdapter.js +131 -28
- package/dist/llm/clients/MistralClientAdapter.d.ts +6 -2
- package/dist/llm/clients/MistralClientAdapter.js +22 -11
- package/dist/llm/clients/MockClientAdapter.d.ts +2 -2
- package/dist/llm/clients/MockClientAdapter.js +36 -19
- package/dist/llm/clients/OpenAIClientAdapter.d.ts +6 -2
- package/dist/llm/clients/OpenAIClientAdapter.js +33 -9
- package/dist/llm/clients/OpenRouterClientAdapter.d.ts +6 -2
- package/dist/llm/clients/OpenRouterClientAdapter.js +87 -16
- package/dist/llm/clients/types.d.ts +18 -1
- package/dist/llm/clients/types.js +4 -0
- package/dist/llm/config.d.ts +9 -2
- package/dist/llm/config.js +697 -33
- package/dist/llm/services/ModelResolver.d.ts +6 -0
- package/dist/llm/services/ModelResolver.js +57 -17
- package/dist/llm/services/RequestValidator.d.ts +8 -0
- package/dist/llm/services/RequestValidator.js +9 -2
- package/dist/llm/services/SettingsManager.d.ts +1 -1
- package/dist/llm/services/SettingsManager.js +92 -4
- package/dist/llm/types.d.ts +127 -0
- package/dist/prompting/index.d.ts +1 -1
- package/dist/prompting/index.js +2 -1
- package/dist/prompting/parser.d.ts +23 -0
- package/dist/prompting/parser.js +33 -0
- package/dist/shared/adapters/errorUtils.d.ts +15 -0
- package/dist/shared/adapters/errorUtils.js +69 -1
- package/dist/shared/adapters/logprobsUtils.d.ts +13 -0
- package/dist/shared/adapters/logprobsUtils.js +33 -0
- package/dist/shared/services/AdapterRegistry.js +3 -1
- package/dist/shared/services/withRetry.d.ts +50 -0
- package/dist/shared/services/withRetry.js +78 -0
- package/dist/types/image.d.ts +2 -0
- package/package.json +59 -59
- package/src/config/image-presets.json +212 -212
- package/src/config/llm-presets.json +623 -599
package/dist/index.js
CHANGED
|
@@ -14,10 +14,14 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.silentLogger = exports.DEFAULT_LOG_LEVEL = exports.createDefaultLogger = exports.KNOWN_GGUF_MODELS = exports.detectGgufCapabilities = exports.createFallbackModelInfo = exports.parseTemplateWithMetadata = exports.extractInitialTaggedContent = exports.parseRoleTags = exports.parseStructuredContent = exports.extractRandomVariables = exports.getSmartPreview = exports.countTokens = exports.renderTemplate = exports.ImageService = exports.MistralClientAdapter = exports.OpenRouterClientAdapter = exports.LlamaCppServerClient = exports.LlamaCppClientAdapter = exports.fromEnvironment = exports.LLMService = void 0;
|
|
17
|
+
exports.silentLogger = exports.DEFAULT_LOG_LEVEL = exports.createDefaultLogger = exports.KNOWN_GGUF_MODELS = exports.detectGgufCapabilities = exports.createFallbackModelInfo = exports.parseTemplateWithMetadata = exports.extractMarkerDelimitedContent = exports.extractInitialTaggedContent = exports.parseRoleTags = exports.parseStructuredContent = exports.extractRandomVariables = exports.getSmartPreview = exports.countTokens = exports.renderTemplate = exports.ImageService = exports.MistralClientAdapter = exports.OpenRouterClientAdapter = exports.LlamaCppServerClient = exports.LlamaCppClientAdapter = exports.fromEnvironment = exports.DEFAULT_RETRY_POLICY = exports.withRetry = exports.LLMService = void 0;
|
|
18
18
|
// --- LLM Service ---
|
|
19
19
|
var LLMService_1 = require("./llm/LLMService");
|
|
20
20
|
Object.defineProperty(exports, "LLMService", { enumerable: true, get: function () { return LLMService_1.LLMService; } });
|
|
21
|
+
// --- Retry Utilities ---
|
|
22
|
+
var withRetry_1 = require("./shared/services/withRetry");
|
|
23
|
+
Object.defineProperty(exports, "withRetry", { enumerable: true, get: function () { return withRetry_1.withRetry; } });
|
|
24
|
+
Object.defineProperty(exports, "DEFAULT_RETRY_POLICY", { enumerable: true, get: function () { return withRetry_1.DEFAULT_RETRY_POLICY; } });
|
|
21
25
|
// Export all core request/response/config types from the LLM module
|
|
22
26
|
__exportStar(require("./llm/types"), exports);
|
|
23
27
|
// Export all client adapter types
|
|
@@ -51,6 +55,7 @@ var parser_1 = require("./prompting/parser");
|
|
|
51
55
|
Object.defineProperty(exports, "parseStructuredContent", { enumerable: true, get: function () { return parser_1.parseStructuredContent; } });
|
|
52
56
|
Object.defineProperty(exports, "parseRoleTags", { enumerable: true, get: function () { return parser_1.parseRoleTags; } });
|
|
53
57
|
Object.defineProperty(exports, "extractInitialTaggedContent", { enumerable: true, get: function () { return parser_1.extractInitialTaggedContent; } });
|
|
58
|
+
Object.defineProperty(exports, "extractMarkerDelimitedContent", { enumerable: true, get: function () { return parser_1.extractMarkerDelimitedContent; } });
|
|
54
59
|
Object.defineProperty(exports, "parseTemplateWithMetadata", { enumerable: true, get: function () { return parser_1.parseTemplateWithMetadata; } });
|
|
55
60
|
var config_1 = require("./llm/config");
|
|
56
61
|
Object.defineProperty(exports, "createFallbackModelInfo", { enumerable: true, get: function () { return config_1.createFallbackModelInfo; } });
|
package/dist/llm/LLMService.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { ApiKeyProvider, PresetMode } from '../types';
|
|
|
2
2
|
import type { Logger, LogLevel } from '../logging/types';
|
|
3
3
|
import type { LLMChatRequest, LLMChatRequestWithPreset, LLMResponse, LLMFailureResponse, ProviderInfo, ModelInfo, ApiProviderId, LLMSettings, ModelContext, LLMMessage } from "./types";
|
|
4
4
|
import type { ModelPreset } from "../types/presets";
|
|
5
|
+
import { type RetryPolicy } from "../shared/services/withRetry";
|
|
5
6
|
export type { PresetMode };
|
|
6
7
|
/**
|
|
7
8
|
* Options for configuring the LLMService
|
|
@@ -15,6 +16,32 @@ export interface LLMServiceOptions {
|
|
|
15
16
|
logLevel?: LogLevel;
|
|
16
17
|
/** Custom logger implementation. If provided, logLevel is ignored. */
|
|
17
18
|
logger?: Logger;
|
|
19
|
+
/**
|
|
20
|
+
* Retry policy for transient failures (rate limits, 5xx, network errors, timeouts).
|
|
21
|
+
* Defaults: maxRetries 2, initialDelayMs 500, maxDelayMs 10000, backoffFactor 2,
|
|
22
|
+
* retryOnTimeout true. Provider SDK-internal retries are disabled — this layer
|
|
23
|
+
* is the single owner of retry behavior. Set `maxRetries: 0` to disable.
|
|
24
|
+
*/
|
|
25
|
+
retry?: Partial<RetryPolicy> & {
|
|
26
|
+
/** Whether REQUEST_TIMEOUT failures are retryable (default true) */
|
|
27
|
+
retryOnTimeout?: boolean;
|
|
28
|
+
};
|
|
29
|
+
/** Default per-request timeout in ms (overridable per call). SDK defaults apply when unset. */
|
|
30
|
+
timeoutMs?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Per-call options for LLMService.sendMessage
|
|
34
|
+
*/
|
|
35
|
+
export interface SendMessageOptions {
|
|
36
|
+
/**
|
|
37
|
+
* Abort signal to cancel the request (client-side — the provider may still
|
|
38
|
+
* process and bill an already-dispatched request). Aborts are never retried.
|
|
39
|
+
*/
|
|
40
|
+
signal?: AbortSignal;
|
|
41
|
+
/** Per-request timeout in ms (overrides the service-level timeoutMs) */
|
|
42
|
+
timeoutMs?: number;
|
|
43
|
+
/** Per-request retry cap (overrides the service-level retry.maxRetries) */
|
|
44
|
+
maxRetries?: number;
|
|
18
45
|
}
|
|
19
46
|
/**
|
|
20
47
|
* Result from createMessages method
|
|
@@ -46,6 +73,8 @@ export declare class LLMService {
|
|
|
46
73
|
private requestValidator;
|
|
47
74
|
private settingsManager;
|
|
48
75
|
private modelResolver;
|
|
76
|
+
private retryOptions;
|
|
77
|
+
private defaultTimeoutMs?;
|
|
49
78
|
constructor(getApiKey: ApiKeyProvider, options?: LLMServiceOptions);
|
|
50
79
|
/**
|
|
51
80
|
* Gets list of supported LLM providers
|
|
@@ -66,7 +95,7 @@ export declare class LLMService {
|
|
|
66
95
|
* @param request - The LLM chat request
|
|
67
96
|
* @returns Promise resolving to either success or failure response
|
|
68
97
|
*/
|
|
69
|
-
sendMessage(request: LLMChatRequest | LLMChatRequestWithPreset): Promise<LLMResponse | LLMFailureResponse>;
|
|
98
|
+
sendMessage(request: LLMChatRequest | LLMChatRequestWithPreset, callOptions?: SendMessageOptions): Promise<LLMResponse | LLMFailureResponse>;
|
|
70
99
|
/**
|
|
71
100
|
* Gets all configured model presets
|
|
72
101
|
*
|
package/dist/llm/LLMService.js
CHANGED
|
@@ -18,6 +18,8 @@ const AdapterRegistry_1 = require("../shared/services/AdapterRegistry");
|
|
|
18
18
|
const RequestValidator_1 = require("./services/RequestValidator");
|
|
19
19
|
const SettingsManager_1 = require("./services/SettingsManager");
|
|
20
20
|
const ModelResolver_1 = require("./services/ModelResolver");
|
|
21
|
+
const withRetry_1 = require("../shared/services/withRetry");
|
|
22
|
+
const types_1 = require("./clients/types");
|
|
21
23
|
/**
|
|
22
24
|
* Main process service for LLM operations
|
|
23
25
|
*
|
|
@@ -32,6 +34,8 @@ const ModelResolver_1 = require("./services/ModelResolver");
|
|
|
32
34
|
class LLMService {
|
|
33
35
|
constructor(getApiKey, options = {}) {
|
|
34
36
|
this.getApiKey = getApiKey;
|
|
37
|
+
this.retryOptions = options.retry;
|
|
38
|
+
this.defaultTimeoutMs = options.timeoutMs;
|
|
35
39
|
// Initialize logger - custom logger takes precedence over logLevel
|
|
36
40
|
this.logger = options.logger ?? (0, defaultLogger_1.createDefaultLogger)(options.logLevel);
|
|
37
41
|
// Initialize services with logger
|
|
@@ -42,7 +46,7 @@ class LLMService {
|
|
|
42
46
|
adapterConstructors: config_1.ADAPTER_CONSTRUCTORS,
|
|
43
47
|
adapterConfigs: config_1.ADAPTER_CONFIGS,
|
|
44
48
|
}, this.logger);
|
|
45
|
-
this.requestValidator = new RequestValidator_1.RequestValidator();
|
|
49
|
+
this.requestValidator = new RequestValidator_1.RequestValidator(this.logger);
|
|
46
50
|
this.settingsManager = new SettingsManager_1.SettingsManager(this.logger);
|
|
47
51
|
this.modelResolver = new ModelResolver_1.ModelResolver(this.presetManager, this.adapterRegistry, this.logger);
|
|
48
52
|
}
|
|
@@ -78,7 +82,7 @@ class LLMService {
|
|
|
78
82
|
* @param request - The LLM chat request
|
|
79
83
|
* @returns Promise resolving to either success or failure response
|
|
80
84
|
*/
|
|
81
|
-
async sendMessage(request) {
|
|
85
|
+
async sendMessage(request, callOptions) {
|
|
82
86
|
this.logger.info(`LLMService.sendMessage called with presetId: ${request.presetId}, provider: ${request.providerId}, model: ${request.modelId}`);
|
|
83
87
|
try {
|
|
84
88
|
// Resolve model information from preset or direct IDs
|
|
@@ -107,7 +111,7 @@ class LLMService {
|
|
|
107
111
|
}
|
|
108
112
|
}
|
|
109
113
|
// Apply model-specific defaults and merge with user settings
|
|
110
|
-
const finalSettings = this.settingsManager.mergeSettingsForModel(modelId, providerId, combinedSettings);
|
|
114
|
+
const finalSettings = this.settingsManager.mergeSettingsForModel(modelId, providerId, combinedSettings, modelInfo);
|
|
111
115
|
// Validate reasoning settings for model capabilities
|
|
112
116
|
const reasoningValidation = this.requestValidator.validateReasoningSettings(modelInfo, finalSettings.reasoning, resolvedRequest);
|
|
113
117
|
if (reasoningValidation) {
|
|
@@ -175,7 +179,41 @@ class LLMService {
|
|
|
175
179
|
};
|
|
176
180
|
}
|
|
177
181
|
this.logger.info(`Making LLM request with ${clientAdapter.constructor.name} for provider: ${providerId}`);
|
|
178
|
-
|
|
182
|
+
// Unified retry layer: adapters never throw, so retry decisions are made on
|
|
183
|
+
// RETURNED failure responses. SDK-internal retries are disabled (maxRetries: 0
|
|
184
|
+
// at client construction) — this loop is the single owner of retry behavior.
|
|
185
|
+
const adapterOptions = {
|
|
186
|
+
...(callOptions?.signal && { signal: callOptions.signal }),
|
|
187
|
+
...((callOptions?.timeoutMs ?? this.defaultTimeoutMs) !== undefined && {
|
|
188
|
+
timeoutMs: callOptions?.timeoutMs ?? this.defaultTimeoutMs,
|
|
189
|
+
}),
|
|
190
|
+
};
|
|
191
|
+
const retryOnTimeout = this.retryOptions?.retryOnTimeout ?? true;
|
|
192
|
+
const retryableCodes = new Set([
|
|
193
|
+
types_1.ADAPTER_ERROR_CODES.RATE_LIMIT_EXCEEDED,
|
|
194
|
+
types_1.ADAPTER_ERROR_CODES.NETWORK_ERROR,
|
|
195
|
+
...(retryOnTimeout ? [types_1.ADAPTER_ERROR_CODES.REQUEST_TIMEOUT] : []),
|
|
196
|
+
]);
|
|
197
|
+
const result = await (0, withRetry_1.withRetry)(() => clientAdapter.sendMessage(internalRequest, apiKey, adapterOptions), (res) => {
|
|
198
|
+
if (res.object !== 'error') {
|
|
199
|
+
return { retry: false };
|
|
200
|
+
}
|
|
201
|
+
const code = String(res.error.code);
|
|
202
|
+
const status = res.error.status;
|
|
203
|
+
const retryable = retryableCodes.has(code) ||
|
|
204
|
+
(code === types_1.ADAPTER_ERROR_CODES.PROVIDER_ERROR &&
|
|
205
|
+
typeof status === 'number' &&
|
|
206
|
+
(status === 408 || status === 409 || status >= 500));
|
|
207
|
+
return { retry: retryable, retryAfterMs: res.error.retryAfterMs };
|
|
208
|
+
}, {
|
|
209
|
+
...this.retryOptions,
|
|
210
|
+
...(callOptions?.maxRetries !== undefined && {
|
|
211
|
+
maxRetries: callOptions.maxRetries,
|
|
212
|
+
}),
|
|
213
|
+
signal: callOptions?.signal,
|
|
214
|
+
logger: this.logger,
|
|
215
|
+
label: `${providerId}/${modelId}`,
|
|
216
|
+
});
|
|
179
217
|
// Post-process for thinking tag fallback
|
|
180
218
|
// This feature extracts reasoning from XML tags when native reasoning is not active.
|
|
181
219
|
// It's a fallback mechanism for models without native reasoning or when native is disabled.
|
|
@@ -375,7 +413,7 @@ class LLMService {
|
|
|
375
413
|
else {
|
|
376
414
|
const { providerId, modelId, modelInfo, settings } = resolved;
|
|
377
415
|
// Merge settings with model defaults
|
|
378
|
-
const mergedSettings = this.settingsManager.mergeSettingsForModel(modelId, providerId, settings || {});
|
|
416
|
+
const mergedSettings = this.settingsManager.mergeSettingsForModel(modelId, providerId, settings || {}, modelInfo);
|
|
379
417
|
// Calculate native reasoning status
|
|
380
418
|
const nativeReasoningActive = !!(modelInfo.reasoning?.supported &&
|
|
381
419
|
(mergedSettings.reasoning?.enabled === true ||
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { LLMResponse, LLMFailureResponse } from "../types";
|
|
2
|
-
import type { ILLMClientAdapter, InternalLLMChatRequest } from "./types";
|
|
2
|
+
import type { ILLMClientAdapter, InternalLLMChatRequest, AdapterRequestOptions } from "./types";
|
|
3
|
+
import type { Logger } from "../../logging/types";
|
|
3
4
|
/**
|
|
4
5
|
* Client adapter for Anthropic API integration
|
|
5
6
|
*
|
|
@@ -12,14 +13,17 @@ import type { ILLMClientAdapter, InternalLLMChatRequest } from "./types";
|
|
|
12
13
|
*/
|
|
13
14
|
export declare class AnthropicClientAdapter implements ILLMClientAdapter {
|
|
14
15
|
private baseURL?;
|
|
16
|
+
private logger;
|
|
15
17
|
/**
|
|
16
18
|
* Creates a new Anthropic client adapter
|
|
17
19
|
*
|
|
18
20
|
* @param config Optional configuration for the adapter
|
|
19
21
|
* @param config.baseURL Custom base URL for Anthropic-compatible APIs
|
|
22
|
+
* @param config.logger Custom logger instance
|
|
20
23
|
*/
|
|
21
24
|
constructor(config?: {
|
|
22
25
|
baseURL?: string;
|
|
26
|
+
logger?: Logger;
|
|
23
27
|
});
|
|
24
28
|
/**
|
|
25
29
|
* Sends a chat message to Anthropic's API
|
|
@@ -28,7 +32,7 @@ export declare class AnthropicClientAdapter implements ILLMClientAdapter {
|
|
|
28
32
|
* @param apiKey - The decrypted Anthropic API key
|
|
29
33
|
* @returns Promise resolving to success or failure response
|
|
30
34
|
*/
|
|
31
|
-
sendMessage(request: InternalLLMChatRequest, apiKey: string): Promise<LLMResponse | LLMFailureResponse>;
|
|
35
|
+
sendMessage(request: InternalLLMChatRequest, apiKey: string, options?: AdapterRequestOptions): Promise<LLMResponse | LLMFailureResponse>;
|
|
32
36
|
/**
|
|
33
37
|
* Validates Anthropic API key format
|
|
34
38
|
*
|
|
@@ -11,7 +11,6 @@ const types_1 = require("./types");
|
|
|
11
11
|
const errorUtils_1 = require("../../shared/adapters/errorUtils");
|
|
12
12
|
const systemMessageUtils_1 = require("../../shared/adapters/systemMessageUtils");
|
|
13
13
|
const defaultLogger_1 = require("../../logging/defaultLogger");
|
|
14
|
-
const logger = (0, defaultLogger_1.createDefaultLogger)();
|
|
15
14
|
/**
|
|
16
15
|
* Client adapter for Anthropic API integration
|
|
17
16
|
*
|
|
@@ -28,9 +27,11 @@ class AnthropicClientAdapter {
|
|
|
28
27
|
*
|
|
29
28
|
* @param config Optional configuration for the adapter
|
|
30
29
|
* @param config.baseURL Custom base URL for Anthropic-compatible APIs
|
|
30
|
+
* @param config.logger Custom logger instance
|
|
31
31
|
*/
|
|
32
32
|
constructor(config) {
|
|
33
33
|
this.baseURL = config?.baseURL;
|
|
34
|
+
this.logger = config?.logger ?? (0, defaultLogger_1.createDefaultLogger)();
|
|
34
35
|
}
|
|
35
36
|
/**
|
|
36
37
|
* Sends a chat message to Anthropic's API
|
|
@@ -39,7 +40,7 @@ class AnthropicClientAdapter {
|
|
|
39
40
|
* @param apiKey - The decrypted Anthropic API key
|
|
40
41
|
* @returns Promise resolving to success or failure response
|
|
41
42
|
*/
|
|
42
|
-
async sendMessage(request, apiKey) {
|
|
43
|
+
async sendMessage(request, apiKey, options) {
|
|
43
44
|
try {
|
|
44
45
|
// Check if structured output is requested - need beta API
|
|
45
46
|
const useStructuredOutput = request.settings.structuredOutput?.schema &&
|
|
@@ -48,7 +49,13 @@ class AnthropicClientAdapter {
|
|
|
48
49
|
const anthropic = new sdk_1.default({
|
|
49
50
|
apiKey,
|
|
50
51
|
...(this.baseURL && { baseURL: this.baseURL }),
|
|
52
|
+
maxRetries: 0, // retries are owned by the unified LLMService retry layer
|
|
51
53
|
});
|
|
54
|
+
// Per-request transport options (abort signal, timeout)
|
|
55
|
+
const requestTransportOptions = {
|
|
56
|
+
...(options?.signal && { signal: options.signal }),
|
|
57
|
+
...(options?.timeoutMs !== undefined && { timeout: options.timeoutMs }),
|
|
58
|
+
};
|
|
52
59
|
// Format messages for Anthropic API (Claude has specific requirements)
|
|
53
60
|
const { messages, systemMessage } = this.formatMessagesForAnthropic(request);
|
|
54
61
|
// Prepare API call parameters
|
|
@@ -58,6 +65,9 @@ class AnthropicClientAdapter {
|
|
|
58
65
|
max_tokens: request.settings.maxTokens,
|
|
59
66
|
temperature: request.settings.temperature,
|
|
60
67
|
top_p: request.settings.topP,
|
|
68
|
+
...(request.settings.topK !== undefined && {
|
|
69
|
+
top_k: request.settings.topK,
|
|
70
|
+
}),
|
|
61
71
|
...(systemMessage && { system: systemMessage }),
|
|
62
72
|
...(request.settings.stopSequences.length > 0 && {
|
|
63
73
|
stop_sequences: request.settings.stopSequences,
|
|
@@ -115,8 +125,8 @@ class AnthropicClientAdapter {
|
|
|
115
125
|
};
|
|
116
126
|
}
|
|
117
127
|
}
|
|
118
|
-
logger.info(`Making Anthropic API call for model: ${request.modelId}`);
|
|
119
|
-
logger.debug(`Anthropic API parameters:`, {
|
|
128
|
+
this.logger.info(`Making Anthropic API call for model: ${request.modelId}`);
|
|
129
|
+
this.logger.debug(`Anthropic API parameters:`, {
|
|
120
130
|
model: messageParams.model,
|
|
121
131
|
temperature: messageParams.temperature,
|
|
122
132
|
max_tokens: messageParams.max_tokens,
|
|
@@ -134,18 +144,22 @@ class AnthropicClientAdapter {
|
|
|
134
144
|
headers: {
|
|
135
145
|
'anthropic-beta': 'structured-outputs-2025-11-13',
|
|
136
146
|
},
|
|
147
|
+
...requestTransportOptions,
|
|
137
148
|
});
|
|
138
149
|
}
|
|
139
150
|
else {
|
|
140
|
-
completion =
|
|
151
|
+
completion =
|
|
152
|
+
Object.keys(requestTransportOptions).length > 0
|
|
153
|
+
? await anthropic.messages.create(messageParams, requestTransportOptions)
|
|
154
|
+
: await anthropic.messages.create(messageParams);
|
|
141
155
|
}
|
|
142
|
-
logger.info(`Anthropic API call successful, response ID: ${completion.id}`);
|
|
156
|
+
this.logger.info(`Anthropic API call successful, response ID: ${completion.id}`);
|
|
143
157
|
// Convert to standardized response format
|
|
144
158
|
// Cast to any to handle beta response type differences
|
|
145
159
|
return this.createSuccessResponse(completion, request);
|
|
146
160
|
}
|
|
147
161
|
catch (error) {
|
|
148
|
-
logger.error("Anthropic API error:", error);
|
|
162
|
+
this.logger.error("Anthropic API error:", error);
|
|
149
163
|
return this.createErrorResponse(error, request);
|
|
150
164
|
}
|
|
151
165
|
}
|
|
@@ -245,7 +259,7 @@ class AnthropicClientAdapter {
|
|
|
245
259
|
const modifiedIndex = (0, systemMessageUtils_1.prependSystemToFirstUserMessage)(simpleMessages, combinedSystemContent, request.settings.systemMessageFallback);
|
|
246
260
|
if (modifiedIndex !== -1) {
|
|
247
261
|
messages[modifiedIndex].content = simpleMessages[modifiedIndex].content;
|
|
248
|
-
logger.debug(`Model ${request.modelId} doesn't support system messages - prepended to first user message`);
|
|
262
|
+
this.logger.debug(`Model ${request.modelId} doesn't support system messages - prepended to first user message`);
|
|
249
263
|
}
|
|
250
264
|
// Don't set systemMessage - it stays undefined
|
|
251
265
|
}
|
|
@@ -253,7 +267,7 @@ class AnthropicClientAdapter {
|
|
|
253
267
|
// Anthropic requires messages to start with 'user' role
|
|
254
268
|
// If the first message is not from user, we need to handle this
|
|
255
269
|
if (messages.length > 0 && messages[0].role !== "user") {
|
|
256
|
-
logger.warn("Anthropic API requires first message to be from user. Adjusting message order.");
|
|
270
|
+
this.logger.warn("Anthropic API requires first message to be from user. Adjusting message order.");
|
|
257
271
|
// Find the first user message and move it to the front, or create a default one
|
|
258
272
|
const firstUserIndex = messages.findIndex((msg) => msg.role === "user");
|
|
259
273
|
if (firstUserIndex > 0) {
|
|
@@ -295,7 +309,7 @@ class AnthropicClientAdapter {
|
|
|
295
309
|
// If roles don't alternate properly, we might need to combine messages
|
|
296
310
|
// or insert a placeholder. For now, we'll skip non-alternating messages
|
|
297
311
|
// and log a warning.
|
|
298
|
-
logger.warn(`Skipping message with unexpected role: expected ${expectedRole}, got ${message.role}`);
|
|
312
|
+
this.logger.warn(`Skipping message with unexpected role: expected ${expectedRole}, got ${message.role}`);
|
|
299
313
|
}
|
|
300
314
|
}
|
|
301
315
|
return cleanedMessages;
|
|
@@ -386,7 +400,7 @@ class AnthropicClientAdapter {
|
|
|
386
400
|
createErrorResponse(error, request) {
|
|
387
401
|
// Use shared error mapping utility for common error patterns
|
|
388
402
|
const initialProviderMessage = error instanceof sdk_1.default.APIError ? error.message : undefined;
|
|
389
|
-
let { errorCode, errorMessage, errorType, status } = (0, errorUtils_1.getCommonMappedErrorDetails)(error, initialProviderMessage);
|
|
403
|
+
let { errorCode, errorMessage, errorType, status, retryAfterMs } = (0, errorUtils_1.getCommonMappedErrorDetails)(error, initialProviderMessage);
|
|
390
404
|
// Apply Anthropic-specific refinements for 400 errors based on message content
|
|
391
405
|
if (error instanceof sdk_1.default.APIError && status === 400) {
|
|
392
406
|
if (error.message.toLowerCase().includes("context length") ||
|
|
@@ -408,6 +422,7 @@ class AnthropicClientAdapter {
|
|
|
408
422
|
code: errorCode,
|
|
409
423
|
type: errorType,
|
|
410
424
|
...(status && { status }),
|
|
425
|
+
...(retryAfterMs !== undefined && { retryAfterMs }),
|
|
411
426
|
providerError: error,
|
|
412
427
|
},
|
|
413
428
|
object: "error",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { LLMResponse, LLMFailureResponse } from "../types";
|
|
2
|
-
import type { ILLMClientAdapter, InternalLLMChatRequest } from "./types";
|
|
2
|
+
import type { ILLMClientAdapter, InternalLLMChatRequest, AdapterRequestOptions } from "./types";
|
|
3
|
+
import type { Logger } from "../../logging/types";
|
|
3
4
|
/**
|
|
4
5
|
* Client adapter for Google Gemini API integration
|
|
5
6
|
*
|
|
@@ -12,14 +13,17 @@ import type { ILLMClientAdapter, InternalLLMChatRequest } from "./types";
|
|
|
12
13
|
*/
|
|
13
14
|
export declare class GeminiClientAdapter implements ILLMClientAdapter {
|
|
14
15
|
private baseURL?;
|
|
16
|
+
private logger;
|
|
15
17
|
/**
|
|
16
18
|
* Creates a new Gemini client adapter
|
|
17
19
|
*
|
|
18
20
|
* @param config Optional configuration for the adapter
|
|
19
21
|
* @param config.baseURL Custom base URL (unused for Gemini but kept for consistency)
|
|
22
|
+
* @param config.logger Custom logger instance
|
|
20
23
|
*/
|
|
21
24
|
constructor(config?: {
|
|
22
25
|
baseURL?: string;
|
|
26
|
+
logger?: Logger;
|
|
23
27
|
});
|
|
24
28
|
/**
|
|
25
29
|
* Sends a chat message to Gemini's API
|
|
@@ -28,7 +32,7 @@ export declare class GeminiClientAdapter implements ILLMClientAdapter {
|
|
|
28
32
|
* @param apiKey - The decrypted Gemini API key
|
|
29
33
|
* @returns Promise resolving to success or failure response
|
|
30
34
|
*/
|
|
31
|
-
sendMessage(request: InternalLLMChatRequest, apiKey: string): Promise<LLMResponse | LLMFailureResponse>;
|
|
35
|
+
sendMessage(request: InternalLLMChatRequest, apiKey: string, options?: AdapterRequestOptions): Promise<LLMResponse | LLMFailureResponse>;
|
|
32
36
|
/**
|
|
33
37
|
* Validates Gemini API key format
|
|
34
38
|
*
|
|
@@ -8,7 +8,6 @@ const types_1 = require("./types");
|
|
|
8
8
|
const errorUtils_1 = require("../../shared/adapters/errorUtils");
|
|
9
9
|
const systemMessageUtils_1 = require("../../shared/adapters/systemMessageUtils");
|
|
10
10
|
const defaultLogger_1 = require("../../logging/defaultLogger");
|
|
11
|
-
const logger = (0, defaultLogger_1.createDefaultLogger)();
|
|
12
11
|
/**
|
|
13
12
|
* Client adapter for Google Gemini API integration
|
|
14
13
|
*
|
|
@@ -25,9 +24,11 @@ class GeminiClientAdapter {
|
|
|
25
24
|
*
|
|
26
25
|
* @param config Optional configuration for the adapter
|
|
27
26
|
* @param config.baseURL Custom base URL (unused for Gemini but kept for consistency)
|
|
27
|
+
* @param config.logger Custom logger instance
|
|
28
28
|
*/
|
|
29
29
|
constructor(config) {
|
|
30
30
|
this.baseURL = config?.baseURL;
|
|
31
|
+
this.logger = config?.logger ?? (0, defaultLogger_1.createDefaultLogger)();
|
|
31
32
|
}
|
|
32
33
|
/**
|
|
33
34
|
* Sends a chat message to Gemini's API
|
|
@@ -36,14 +37,14 @@ class GeminiClientAdapter {
|
|
|
36
37
|
* @param apiKey - The decrypted Gemini API key
|
|
37
38
|
* @returns Promise resolving to success or failure response
|
|
38
39
|
*/
|
|
39
|
-
async sendMessage(request, apiKey) {
|
|
40
|
+
async sendMessage(request, apiKey, options) {
|
|
40
41
|
try {
|
|
41
|
-
// Initialize Gemini client
|
|
42
|
+
// Initialize Gemini client (note: @google/genai performs no automatic retries)
|
|
42
43
|
const genAI = new genai_1.GoogleGenAI({ apiKey });
|
|
43
44
|
// Format the request for Gemini API
|
|
44
45
|
const { contents, generationConfig, safetySettings, systemInstruction } = this.formatInternalRequestToGemini(request);
|
|
45
|
-
logger.info(`Making Gemini API call for model: ${request.modelId}`);
|
|
46
|
-
logger.debug(`Gemini API parameters:`, {
|
|
46
|
+
this.logger.info(`Making Gemini API call for model: ${request.modelId}`);
|
|
47
|
+
this.logger.debug(`Gemini API parameters:`, {
|
|
47
48
|
model: request.modelId,
|
|
48
49
|
temperature: generationConfig.temperature,
|
|
49
50
|
maxOutputTokens: generationConfig.maxOutputTokens,
|
|
@@ -59,14 +60,18 @@ class GeminiClientAdapter {
|
|
|
59
60
|
...generationConfig,
|
|
60
61
|
safetySettings: safetySettings,
|
|
61
62
|
...(systemInstruction && { systemInstruction: systemInstruction }),
|
|
63
|
+
...(options?.signal && { abortSignal: options.signal }),
|
|
64
|
+
...(options?.timeoutMs !== undefined && {
|
|
65
|
+
httpOptions: { timeout: options.timeoutMs },
|
|
66
|
+
}),
|
|
62
67
|
},
|
|
63
68
|
});
|
|
64
|
-
logger.info(`Gemini API call successful, processing response`);
|
|
69
|
+
this.logger.info(`Gemini API call successful, processing response`);
|
|
65
70
|
// Convert to standardized response format
|
|
66
71
|
return this.createSuccessResponse(result, request);
|
|
67
72
|
}
|
|
68
73
|
catch (error) {
|
|
69
|
-
logger.error("Gemini API error:", error);
|
|
74
|
+
this.logger.error("Gemini API error:", error);
|
|
70
75
|
return this.createErrorResponse(error, request);
|
|
71
76
|
}
|
|
72
77
|
}
|
|
@@ -142,7 +147,7 @@ class GeminiClientAdapter {
|
|
|
142
147
|
if (modifiedIndex !== -1) {
|
|
143
148
|
// Update the actual contents array
|
|
144
149
|
contents[modifiedIndex].parts[0].text = simpleContents[modifiedIndex].content;
|
|
145
|
-
logger.debug(`Model ${request.modelId} doesn't support system instructions - prepended to first user message`);
|
|
150
|
+
this.logger.debug(`Model ${request.modelId} doesn't support system instructions - prepended to first user message`);
|
|
146
151
|
}
|
|
147
152
|
// Don't set systemInstruction - it stays undefined
|
|
148
153
|
}
|
|
@@ -152,6 +157,12 @@ class GeminiClientAdapter {
|
|
|
152
157
|
maxOutputTokens: request.settings.maxTokens,
|
|
153
158
|
temperature: request.settings.temperature,
|
|
154
159
|
...(request.settings.topP && { topP: request.settings.topP }),
|
|
160
|
+
...(request.settings.topK !== undefined && {
|
|
161
|
+
topK: request.settings.topK,
|
|
162
|
+
}),
|
|
163
|
+
...(request.settings.seed !== undefined && {
|
|
164
|
+
seed: request.settings.seed,
|
|
165
|
+
}),
|
|
155
166
|
...(request.settings.stopSequences &&
|
|
156
167
|
request.settings.stopSequences.length > 0 && {
|
|
157
168
|
stopSequences: request.settings.stopSequences,
|
|
@@ -306,7 +317,7 @@ class GeminiClientAdapter {
|
|
|
306
317
|
createErrorResponse(error, request) {
|
|
307
318
|
// Use shared error mapping utility for common error patterns
|
|
308
319
|
const initialProviderMessage = error?.message;
|
|
309
|
-
let { errorCode, errorMessage, errorType, status } = (0, errorUtils_1.getCommonMappedErrorDetails)(error, initialProviderMessage);
|
|
320
|
+
let { errorCode, errorMessage, errorType, status, retryAfterMs } = (0, errorUtils_1.getCommonMappedErrorDetails)(error, initialProviderMessage);
|
|
310
321
|
// Apply Gemini-specific refinements for certain error types
|
|
311
322
|
if (error && error.message) {
|
|
312
323
|
const message = error.message.toLowerCase();
|
|
@@ -336,6 +347,7 @@ class GeminiClientAdapter {
|
|
|
336
347
|
code: errorCode,
|
|
337
348
|
type: errorType,
|
|
338
349
|
...(status && { status }),
|
|
350
|
+
...(retryAfterMs !== undefined && { retryAfterMs }),
|
|
339
351
|
providerError: error,
|
|
340
352
|
},
|
|
341
353
|
object: "error",
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import type { LLMResponse, LLMFailureResponse, ModelInfo } from "../types";
|
|
2
|
-
import type { ILLMClientAdapter, InternalLLMChatRequest } from "./types";
|
|
2
|
+
import type { ILLMClientAdapter, InternalLLMChatRequest, AdapterRequestOptions } from "./types";
|
|
3
3
|
import { LlamaCppServerClient } from "./LlamaCppServerClient";
|
|
4
|
+
import type { Logger } from "../../logging/types";
|
|
4
5
|
/**
|
|
5
6
|
* Configuration options for LlamaCppClientAdapter
|
|
6
7
|
*/
|
|
7
8
|
export interface LlamaCppClientConfig {
|
|
8
|
-
/** Base URL of the llama.cpp server (default: http://
|
|
9
|
+
/** Base URL of the llama.cpp server (default: http://127.0.0.1:8080) */
|
|
9
10
|
baseURL?: string;
|
|
10
11
|
/** Whether to check server health before sending requests (default: false) */
|
|
11
12
|
checkHealth?: boolean;
|
|
13
|
+
/** Logger instance for adapter logging */
|
|
14
|
+
logger?: Logger;
|
|
12
15
|
}
|
|
13
16
|
/**
|
|
14
17
|
* Client adapter for llama.cpp server integration
|
|
@@ -30,7 +33,7 @@ export interface LlamaCppClientConfig {
|
|
|
30
33
|
* ```typescript
|
|
31
34
|
* // Create adapter for local server
|
|
32
35
|
* const adapter = new LlamaCppClientAdapter({
|
|
33
|
-
* baseURL: 'http://
|
|
36
|
+
* baseURL: 'http://127.0.0.1:8080',
|
|
34
37
|
* checkHealth: true
|
|
35
38
|
* });
|
|
36
39
|
*
|
|
@@ -51,6 +54,7 @@ export declare class LlamaCppClientAdapter implements ILLMClientAdapter {
|
|
|
51
54
|
private serverClient;
|
|
52
55
|
private cachedModelCapabilities;
|
|
53
56
|
private detectionAttempted;
|
|
57
|
+
private logger;
|
|
54
58
|
/**
|
|
55
59
|
* Creates a new llama.cpp client adapter
|
|
56
60
|
*
|
|
@@ -80,7 +84,7 @@ export declare class LlamaCppClientAdapter implements ILLMClientAdapter {
|
|
|
80
84
|
* @param apiKey - Not used for llama.cpp (local server), but kept for interface compatibility
|
|
81
85
|
* @returns Promise resolving to success or failure response
|
|
82
86
|
*/
|
|
83
|
-
sendMessage(request: InternalLLMChatRequest, apiKey: string): Promise<LLMResponse | LLMFailureResponse>;
|
|
87
|
+
sendMessage(request: InternalLLMChatRequest, apiKey: string, options?: AdapterRequestOptions): Promise<LLMResponse | LLMFailureResponse>;
|
|
84
88
|
/**
|
|
85
89
|
* Validates API key format
|
|
86
90
|
*
|