genai-lite 0.9.0 → 0.9.2
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.
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
19
|
exports.GenaiElectronImageAdapter = void 0;
|
|
20
20
|
const errorUtils_1 = require("../../shared/adapters/errorUtils");
|
|
21
|
+
const types_1 = require("../../llm/clients/types");
|
|
21
22
|
const defaultLogger_1 = require("../../logging/defaultLogger");
|
|
22
23
|
/**
|
|
23
24
|
* Adapter for genai-electron's local diffusion image generation
|
|
@@ -157,6 +158,12 @@ class GenaiElectronImageAdapter {
|
|
|
157
158
|
const error = state.error || { message: 'Unknown error', code: 'UNKNOWN_ERROR' };
|
|
158
159
|
throw this.createGenerationError(error.message, error.code);
|
|
159
160
|
}
|
|
161
|
+
// Handle out-of-band cancellation (terminal status since genai-electron 0.6.0)
|
|
162
|
+
if (state.status === 'cancelled') {
|
|
163
|
+
const cancelError = new Error(`Image generation was cancelled on the server (ID: ${generationId})`);
|
|
164
|
+
cancelError.code = 'GENERATION_CANCELLED';
|
|
165
|
+
throw cancelError;
|
|
166
|
+
}
|
|
160
167
|
// Wait before next poll
|
|
161
168
|
await this.sleep(this.pollInterval);
|
|
162
169
|
}
|
|
@@ -231,8 +238,15 @@ class GenaiElectronImageAdapter {
|
|
|
231
238
|
const mapped = (0, errorUtils_1.getCommonMappedErrorDetails)(error);
|
|
232
239
|
// Enhance error message with context
|
|
233
240
|
let errorMessage = mapped.errorMessage;
|
|
241
|
+
let errorCode = mapped.errorCode;
|
|
242
|
+
let errorType = mapped.errorType;
|
|
234
243
|
// Special handling for genai-electron specific errors
|
|
235
|
-
if (error.code === '
|
|
244
|
+
if (error.code === 'GENERATION_CANCELLED') {
|
|
245
|
+
errorMessage = error.message;
|
|
246
|
+
errorCode = types_1.ADAPTER_ERROR_CODES.REQUEST_ABORTED;
|
|
247
|
+
errorType = 'abort_error';
|
|
248
|
+
}
|
|
249
|
+
else if (error.code === 'SERVER_BUSY') {
|
|
236
250
|
errorMessage = 'Image generation server is busy. Wait for current generation to complete.';
|
|
237
251
|
error.type = 'rate_limit_error';
|
|
238
252
|
}
|
|
@@ -258,8 +272,8 @@ class GenaiElectronImageAdapter {
|
|
|
258
272
|
}
|
|
259
273
|
// Create enhanced error with all details
|
|
260
274
|
const enhancedError = new Error(errorMessage);
|
|
261
|
-
enhancedError.code =
|
|
262
|
-
enhancedError.type =
|
|
275
|
+
enhancedError.code = errorCode;
|
|
276
|
+
enhancedError.type = errorType;
|
|
263
277
|
enhancedError.status = mapped.status;
|
|
264
278
|
enhancedError.providerId = this.id;
|
|
265
279
|
enhancedError.modelId = request.modelId;
|
|
@@ -75,6 +75,7 @@ export declare class GeminiClientAdapter implements ILLMClientAdapter {
|
|
|
75
75
|
*
|
|
76
76
|
* @param error - The error from Gemini API
|
|
77
77
|
* @param request - Original request for context
|
|
78
|
+
* @param context - Adapter-side transport state captured at catch time
|
|
78
79
|
* @returns Standardized LLM failure response
|
|
79
80
|
*/
|
|
80
81
|
private createErrorResponse;
|
|
@@ -38,6 +38,12 @@ class GeminiClientAdapter {
|
|
|
38
38
|
* @returns Promise resolving to success or failure response
|
|
39
39
|
*/
|
|
40
40
|
async sendMessage(request, apiKey, options) {
|
|
41
|
+
// The SDK enforces httpOptions.timeout by aborting an internal controller and
|
|
42
|
+
// wraps any fetch rejection in a plain Error (no name/status/code), so timeouts
|
|
43
|
+
// and caller aborts cannot be classified from the error object. The adapter owns
|
|
44
|
+
// the timeout instead and classifies from its own state in the catch block.
|
|
45
|
+
let timedOut = false;
|
|
46
|
+
let timeoutHandle;
|
|
41
47
|
try {
|
|
42
48
|
// Initialize Gemini client (note: @google/genai performs no automatic retries)
|
|
43
49
|
const genAI = new genai_1.GoogleGenAI({ apiKey });
|
|
@@ -52,6 +58,26 @@ class GeminiClientAdapter {
|
|
|
52
58
|
contentsLength: contents.length,
|
|
53
59
|
safetySettingsCount: safetySettings?.length || 0,
|
|
54
60
|
});
|
|
61
|
+
let abortSignal = options?.signal;
|
|
62
|
+
if (options?.timeoutMs !== undefined) {
|
|
63
|
+
const controller = new AbortController();
|
|
64
|
+
if (options.signal) {
|
|
65
|
+
if (options.signal.aborted) {
|
|
66
|
+
controller.abort();
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
options.signal.addEventListener("abort", () => controller.abort(), {
|
|
70
|
+
once: true,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
timeoutHandle = setTimeout(() => {
|
|
75
|
+
timedOut = true;
|
|
76
|
+
controller.abort();
|
|
77
|
+
}, options.timeoutMs);
|
|
78
|
+
timeoutHandle.unref?.();
|
|
79
|
+
abortSignal = controller.signal;
|
|
80
|
+
}
|
|
55
81
|
// Generate content using the modern API
|
|
56
82
|
const result = await genAI.models.generateContent({
|
|
57
83
|
model: request.modelId,
|
|
@@ -60,9 +86,11 @@ class GeminiClientAdapter {
|
|
|
60
86
|
...generationConfig,
|
|
61
87
|
safetySettings: safetySettings,
|
|
62
88
|
...(systemInstruction && { systemInstruction: systemInstruction }),
|
|
63
|
-
...(
|
|
89
|
+
...(abortSignal && { abortSignal }),
|
|
90
|
+
// Keep the SDK's server-side timeout hint (X-Server-Timeout header),
|
|
91
|
+
// padded so the adapter's local timer always fires first
|
|
64
92
|
...(options?.timeoutMs !== undefined && {
|
|
65
|
-
httpOptions: { timeout: options.timeoutMs },
|
|
93
|
+
httpOptions: { timeout: options.timeoutMs + 1000 },
|
|
66
94
|
}),
|
|
67
95
|
},
|
|
68
96
|
});
|
|
@@ -72,7 +100,15 @@ class GeminiClientAdapter {
|
|
|
72
100
|
}
|
|
73
101
|
catch (error) {
|
|
74
102
|
this.logger.error("Gemini API error:", error);
|
|
75
|
-
return this.createErrorResponse(error, request
|
|
103
|
+
return this.createErrorResponse(error, request, {
|
|
104
|
+
timedOut,
|
|
105
|
+
aborted: options?.signal?.aborted === true,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
if (timeoutHandle !== undefined) {
|
|
110
|
+
clearTimeout(timeoutHandle);
|
|
111
|
+
}
|
|
76
112
|
}
|
|
77
113
|
}
|
|
78
114
|
/**
|
|
@@ -312,9 +348,38 @@ class GeminiClientAdapter {
|
|
|
312
348
|
*
|
|
313
349
|
* @param error - The error from Gemini API
|
|
314
350
|
* @param request - Original request for context
|
|
351
|
+
* @param context - Adapter-side transport state captured at catch time
|
|
315
352
|
* @returns Standardized LLM failure response
|
|
316
353
|
*/
|
|
317
|
-
createErrorResponse(error, request) {
|
|
354
|
+
createErrorResponse(error, request, context) {
|
|
355
|
+
// Classify adapter-owned aborts/timeouts first — the SDK surfaces both as
|
|
356
|
+
// plain Errors the common mapping cannot recognize (see sendMessage)
|
|
357
|
+
if (context?.aborted) {
|
|
358
|
+
return {
|
|
359
|
+
provider: request.providerId,
|
|
360
|
+
model: request.modelId,
|
|
361
|
+
error: {
|
|
362
|
+
message: "Request was aborted",
|
|
363
|
+
code: types_1.ADAPTER_ERROR_CODES.REQUEST_ABORTED,
|
|
364
|
+
type: "abort_error",
|
|
365
|
+
providerError: error,
|
|
366
|
+
},
|
|
367
|
+
object: "error",
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
if (context?.timedOut) {
|
|
371
|
+
return {
|
|
372
|
+
provider: request.providerId,
|
|
373
|
+
model: request.modelId,
|
|
374
|
+
error: {
|
|
375
|
+
message: "Request timed out",
|
|
376
|
+
code: types_1.ADAPTER_ERROR_CODES.REQUEST_TIMEOUT,
|
|
377
|
+
type: "timeout_error",
|
|
378
|
+
providerError: error,
|
|
379
|
+
},
|
|
380
|
+
object: "error",
|
|
381
|
+
};
|
|
382
|
+
}
|
|
318
383
|
// Use shared error mapping utility for common error patterns
|
|
319
384
|
const initialProviderMessage = error?.message;
|
|
320
385
|
let { errorCode, errorMessage, errorType, status, retryAfterMs } = (0, errorUtils_1.getCommonMappedErrorDetails)(error, initialProviderMessage);
|
package/dist/llm/config.js
CHANGED
|
@@ -517,7 +517,7 @@ exports.KNOWN_GGUF_MODELS = [
|
|
|
517
517
|
description: "Gemma 4 E2B (2.3B effective) hybrid-thinking model",
|
|
518
518
|
capabilities: {
|
|
519
519
|
maxTokens: 8192,
|
|
520
|
-
contextWindow:
|
|
520
|
+
contextWindow: 131072,
|
|
521
521
|
supportsImages: false,
|
|
522
522
|
supportsPromptCache: false,
|
|
523
523
|
supportsSystemMessage: true,
|
|
@@ -532,7 +532,22 @@ exports.KNOWN_GGUF_MODELS = [
|
|
|
532
532
|
description: "Gemma 4 E4B (4.5B effective) hybrid-thinking model",
|
|
533
533
|
capabilities: {
|
|
534
534
|
maxTokens: 8192,
|
|
535
|
-
contextWindow:
|
|
535
|
+
contextWindow: 131072,
|
|
536
|
+
supportsImages: false,
|
|
537
|
+
supportsPromptCache: false,
|
|
538
|
+
supportsSystemMessage: true,
|
|
539
|
+
reasoning: { ...HYBRID_REASONING },
|
|
540
|
+
localReasoning: GEMMA4_LOCAL_REASONING,
|
|
541
|
+
defaultSettings: GEMMA_SAMPLING,
|
|
542
|
+
},
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
pattern: "gemma-4-12b",
|
|
546
|
+
name: "Gemma 4 12B",
|
|
547
|
+
description: "Gemma 4 12B dense hybrid-thinking model (256K context)",
|
|
548
|
+
capabilities: {
|
|
549
|
+
maxTokens: 16384,
|
|
550
|
+
contextWindow: 262144,
|
|
536
551
|
supportsImages: false,
|
|
537
552
|
supportsPromptCache: false,
|
|
538
553
|
supportsSystemMessage: true,
|
|
@@ -544,10 +559,10 @@ exports.KNOWN_GGUF_MODELS = [
|
|
|
544
559
|
{
|
|
545
560
|
pattern: "gemma-4-26b-a4b",
|
|
546
561
|
name: "Gemma 4 26B-A4B",
|
|
547
|
-
description: "Gemma 4 26B MoE (~4B active) hybrid-thinking model",
|
|
562
|
+
description: "Gemma 4 26B MoE (~4B active) hybrid-thinking model (256K context)",
|
|
548
563
|
capabilities: {
|
|
549
564
|
maxTokens: 16384,
|
|
550
|
-
contextWindow:
|
|
565
|
+
contextWindow: 262144,
|
|
551
566
|
supportsImages: false,
|
|
552
567
|
supportsPromptCache: false,
|
|
553
568
|
supportsSystemMessage: true,
|
|
@@ -577,7 +592,7 @@ exports.KNOWN_GGUF_MODELS = [
|
|
|
577
592
|
description: "Gemma 4 hybrid-thinking model (size not recognized)",
|
|
578
593
|
capabilities: {
|
|
579
594
|
maxTokens: 8192,
|
|
580
|
-
contextWindow:
|
|
595
|
+
contextWindow: 131072,
|
|
581
596
|
supportsImages: false,
|
|
582
597
|
supportsPromptCache: false,
|
|
583
598
|
supportsSystemMessage: true,
|
|
@@ -1170,31 +1185,14 @@ exports.SUPPORTED_MODELS = [
|
|
|
1170
1185
|
// Note: Unlike Gemma 3, Gemma 4 supports a native system role
|
|
1171
1186
|
// Note: Reasoning left unsupported on the cloud entries — the Gemini API exposes
|
|
1172
1187
|
// no thinking toggle for Gemma (the <|think|> system-token mechanism is not modeled)
|
|
1173
|
-
{
|
|
1174
|
-
id: "gemma-4-4b-it",
|
|
1175
|
-
name: "Gemma 4 4B",
|
|
1176
|
-
providerId: "gemini",
|
|
1177
|
-
contextWindow: 32768,
|
|
1178
|
-
inputPrice: 0.0,
|
|
1179
|
-
outputPrice: 0.0,
|
|
1180
|
-
description: "Google's Gemma 4 4B open model with system-message support (free via Gemini API)",
|
|
1181
|
-
maxTokens: 8192,
|
|
1182
|
-
supportsImages: false,
|
|
1183
|
-
supportsPromptCache: false,
|
|
1184
|
-
supportsSystemMessage: true,
|
|
1185
|
-
structuredOutput: {
|
|
1186
|
-
supported: false,
|
|
1187
|
-
notes: "Gemma models do not support JSON mode via Google's API",
|
|
1188
|
-
},
|
|
1189
|
-
},
|
|
1190
1188
|
{
|
|
1191
1189
|
id: "gemma-4-26b-a4b-it",
|
|
1192
1190
|
name: "Gemma 4 26B-A4B",
|
|
1193
1191
|
providerId: "gemini",
|
|
1194
|
-
contextWindow:
|
|
1192
|
+
contextWindow: 262144,
|
|
1195
1193
|
inputPrice: 0.0,
|
|
1196
1194
|
outputPrice: 0.0,
|
|
1197
|
-
description: "Google's Gemma 4 26B MoE (~4B active) open model (free via Gemini API)",
|
|
1195
|
+
description: "Google's Gemma 4 26B MoE (~4B active) open model with 256K context (free via Gemini API)",
|
|
1198
1196
|
maxTokens: 8192,
|
|
1199
1197
|
supportsImages: false,
|
|
1200
1198
|
supportsPromptCache: false,
|