ak-gemini 2.2.1 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/base.js +73 -16
- package/chat.js +13 -0
- package/image-generator.js +186 -0
- package/index.cjs +217 -15
- package/index.js +3 -1
- package/package.json +3 -2
- package/transformer.js +2 -1
- package/types.d.ts +80 -3
package/base.js
CHANGED
|
@@ -25,26 +25,50 @@ const DEFAULT_THINKING_CONFIG = {
|
|
|
25
25
|
|
|
26
26
|
const DEFAULT_MAX_OUTPUT_TOKENS = 50_000;
|
|
27
27
|
|
|
28
|
-
/** Models that support thinking features */
|
|
28
|
+
/** Models that support thinking features. Image / live / tts variants intentionally excluded. */
|
|
29
29
|
const THINKING_SUPPORTED_MODELS = [
|
|
30
|
-
/^gemini-3
|
|
31
|
-
/^gemini-3
|
|
30
|
+
/^gemini-3(\.\d+)?-pro(-preview)?$/,
|
|
31
|
+
/^gemini-3(\.\d+)?-flash(-preview)?$/,
|
|
32
|
+
/^gemini-3(\.\d+)?-flash-lite(-preview)?$/,
|
|
32
33
|
/^gemini-2\.5-pro/,
|
|
33
34
|
/^gemini-2\.5-flash(-preview)?$/,
|
|
34
35
|
/^gemini-2\.5-flash-lite(-preview)?$/,
|
|
35
36
|
/^gemini-2\.0-flash$/
|
|
36
37
|
];
|
|
37
38
|
|
|
38
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* Model pricing per million tokens (Paid Tier Standard, base rate, as of July 2026).
|
|
41
|
+
* Source: https://ai.google.dev/gemini-api/docs/pricing
|
|
42
|
+
*
|
|
43
|
+
* NOTES:
|
|
44
|
+
* - Pro models use tiered pricing (≤200k vs >200k context). Listed rate is ≤200k base tier.
|
|
45
|
+
* - Gemma models (e.g. Gemma 4) are intentionally excluded — they are open models with
|
|
46
|
+
* no paid per-token tier on the Gemini API (Vertex deployments bill by compute).
|
|
47
|
+
* - Image-output tokens on Nano Banana models bill at $60/M (1.5 Flash Image) or $120/M (3 Pro Image).
|
|
48
|
+
* Only text-input/text-output rates are modelled here; image-output cost is NOT included in estimateCost().
|
|
49
|
+
* - Audio input is more expensive on most models — listed rate covers text/image/video input.
|
|
50
|
+
*/
|
|
39
51
|
const MODEL_PRICING = {
|
|
40
|
-
|
|
41
|
-
'gemini-
|
|
42
|
-
'gemini-
|
|
43
|
-
|
|
44
|
-
'gemini-3-pro-preview': { input: 2.00, output: 12.00 },
|
|
52
|
+
// Gemini 3.x stable
|
|
53
|
+
'gemini-3.5-flash': { input: 1.50, output: 9.00 },
|
|
54
|
+
'gemini-3.1-flash-lite': { input: 0.25, output: 1.50 },
|
|
55
|
+
// Gemini 3.x preview
|
|
56
|
+
'gemini-3.1-pro-preview': { input: 2.00, output: 12.00 }, // ≤200k tier
|
|
57
|
+
'gemini-3-pro-preview': { input: 2.00, output: 12.00 }, // ≤200k tier; launch rate (superseded by 3.1, off the pricing page)
|
|
58
|
+
'gemini-3-flash-preview': { input: 0.50, output: 3.00 },
|
|
59
|
+
'gemini-3.1-flash-lite-preview': { input: 0.25, output: 1.50 },
|
|
60
|
+
'gemini-3.1-flash-image-preview': { input: 0.50, output: 3.00 }, // text-only; image-output is $60/M
|
|
61
|
+
'gemini-3-pro-image-preview': { input: 2.00, output: 12.00 }, // text-only; image-output is $120/M
|
|
62
|
+
// Gemini 2.5 stable
|
|
63
|
+
'gemini-2.5-flash': { input: 0.30, output: 2.50 },
|
|
64
|
+
'gemini-2.5-flash-lite': { input: 0.10, output: 0.40 },
|
|
65
|
+
'gemini-2.5-pro': { input: 1.25, output: 10.00 }, // ≤200k tier
|
|
66
|
+
'gemini-2.5-flash-image': { input: 0.30, output: 0 }, // image-output is ~$0.039/image (1290 tokens)
|
|
67
|
+
// Deprecated but kept for back-compat (shut down June 2026)
|
|
45
68
|
'gemini-2.0-flash': { input: 0.10, output: 0.40 },
|
|
46
69
|
'gemini-2.0-flash-lite': { input: 0.02, output: 0.10 },
|
|
47
|
-
|
|
70
|
+
// Embeddings
|
|
71
|
+
'gemini-embedding-001': { input: 0.15, output: 0 }
|
|
48
72
|
};
|
|
49
73
|
|
|
50
74
|
export { DEFAULT_SAFETY_SETTINGS, DEFAULT_THINKING_CONFIG, THINKING_SUPPORTED_MODELS, MODEL_PRICING, DEFAULT_MAX_OUTPUT_TOKENS };
|
|
@@ -70,7 +94,7 @@ class BaseGemini {
|
|
|
70
94
|
*/
|
|
71
95
|
constructor(options = {}) {
|
|
72
96
|
// ── Model ──
|
|
73
|
-
this.modelName = options.modelName || 'gemini-
|
|
97
|
+
this.modelName = options.modelName || 'gemini-3-flash-preview';
|
|
74
98
|
|
|
75
99
|
// ── System Prompt ──
|
|
76
100
|
// Subclasses set their own default if options.systemPrompt is undefined
|
|
@@ -114,6 +138,14 @@ class BaseGemini {
|
|
|
114
138
|
// ── Caching ──
|
|
115
139
|
this.cachedContent = options.cachedContent || null;
|
|
116
140
|
|
|
141
|
+
// ── Service Tier (Gemini API / Vertex AI 2026+) ──
|
|
142
|
+
// Allowed values: 'STANDARD' | 'FLEX' | 'PRIORITY' — cost vs latency trade.
|
|
143
|
+
this.serviceTier = options.serviceTier || null;
|
|
144
|
+
|
|
145
|
+
// ── Server-Side Tool Invocation Visibility (1.46.0+) ──
|
|
146
|
+
// When grounding is on, surface the server's tool calls (e.g. Google Search) in the response.
|
|
147
|
+
this.includeServerSideToolInvocations = options.includeServerSideToolInvocations ?? false;
|
|
148
|
+
|
|
117
149
|
// ── Chat Config ──
|
|
118
150
|
this.chatConfig = {
|
|
119
151
|
temperature: 0.7,
|
|
@@ -123,6 +155,16 @@ class BaseGemini {
|
|
|
123
155
|
...options.chatConfig
|
|
124
156
|
};
|
|
125
157
|
|
|
158
|
+
if (this.serviceTier) this.chatConfig['serviceTier'] = this.serviceTier;
|
|
159
|
+
if (this.includeServerSideToolInvocations) this.chatConfig['includeServerSideToolInvocations'] = true;
|
|
160
|
+
|
|
161
|
+
// ── Sampling Shortcuts ──
|
|
162
|
+
// Top-level sugar for chatConfig sampling knobs; wins over chatConfig
|
|
163
|
+
// (same precedence as the maxOutputTokens promotion below)
|
|
164
|
+
for (const key of ['temperature', 'topP', 'topK']) {
|
|
165
|
+
if (options[key] !== undefined) this.chatConfig[key] = options[key];
|
|
166
|
+
}
|
|
167
|
+
|
|
126
168
|
// Apply systemPrompt to chatConfig
|
|
127
169
|
if (this.systemPrompt) {
|
|
128
170
|
this.chatConfig.systemInstruction = this.systemPrompt;
|
|
@@ -289,6 +331,7 @@ class BaseGemini {
|
|
|
289
331
|
* @param {string} [opts.contextKey='CONTEXT'] - Key for optional context
|
|
290
332
|
* @param {string} [opts.explanationKey='EXPLANATION'] - Key for optional explanations
|
|
291
333
|
* @param {string} [opts.systemPromptKey='SYSTEM'] - Key for system prompt overrides in examples
|
|
334
|
+
* @param {'json'|'text'} [opts.format='json'] - Model-turn format: 'json' wraps answers in a {data} envelope (Transformer protocol); 'text' stores ANSWER verbatim (prose agents like Chat)
|
|
292
335
|
* @returns {Promise<Array>} The updated chat history
|
|
293
336
|
*/
|
|
294
337
|
async seed(examples, opts = {}) {
|
|
@@ -304,6 +347,7 @@ class BaseGemini {
|
|
|
304
347
|
const contextKey = opts.contextKey || 'CONTEXT';
|
|
305
348
|
const explanationKey = opts.explanationKey || 'EXPLANATION';
|
|
306
349
|
const systemPromptKey = opts.systemPromptKey || 'SYSTEM';
|
|
350
|
+
const format = opts.format || 'json';
|
|
307
351
|
|
|
308
352
|
// Check for system prompt override in examples
|
|
309
353
|
const instructionExample = examples.find(ex => ex[systemPromptKey]);
|
|
@@ -335,9 +379,15 @@ class BaseGemini {
|
|
|
335
379
|
userText += promptText;
|
|
336
380
|
}
|
|
337
381
|
|
|
338
|
-
|
|
339
|
-
if (
|
|
340
|
-
|
|
382
|
+
let modelText;
|
|
383
|
+
if (format === 'text') {
|
|
384
|
+
modelText = isJSON(answerValue) ? JSON.stringify(answerValue, null, 2) : String(answerValue || '');
|
|
385
|
+
if (explanationValue) log.warn('seed(): EXPLANATION has no representation in text format; ignored.');
|
|
386
|
+
} else {
|
|
387
|
+
if (answerValue) modelResponse.data = answerValue;
|
|
388
|
+
if (explanationValue) modelResponse.explanation = explanationValue;
|
|
389
|
+
modelText = JSON.stringify(modelResponse, null, 2);
|
|
390
|
+
}
|
|
341
391
|
|
|
342
392
|
if (userText.trim().length && modelText.trim().length > 0) {
|
|
343
393
|
historyToAdd.push({ role: 'user', parts: [{ text: userText.trim() }] });
|
|
@@ -365,6 +415,7 @@ class BaseGemini {
|
|
|
365
415
|
* @protected
|
|
366
416
|
*/
|
|
367
417
|
_captureMetadata(response) {
|
|
418
|
+
const modelStatus = response?.modelStatus || null;
|
|
368
419
|
this.lastResponseMetadata = {
|
|
369
420
|
modelVersion: response.modelVersion || null,
|
|
370
421
|
requestedModel: this.modelName,
|
|
@@ -372,8 +423,13 @@ class BaseGemini {
|
|
|
372
423
|
responseTokens: response.usageMetadata?.candidatesTokenCount || 0,
|
|
373
424
|
totalTokens: response.usageMetadata?.totalTokenCount || 0,
|
|
374
425
|
timestamp: Date.now(),
|
|
375
|
-
groundingMetadata: response.candidates?.[0]?.groundingMetadata || null
|
|
426
|
+
groundingMetadata: response.candidates?.[0]?.groundingMetadata || null,
|
|
427
|
+
modelStatus
|
|
376
428
|
};
|
|
429
|
+
if (modelStatus === 'DEPRECATED' && !this._deprecationWarned) {
|
|
430
|
+
log.warn(`Model "${this.modelName}" is marked DEPRECATED by Google. Plan migration.`);
|
|
431
|
+
this._deprecationWarned = true;
|
|
432
|
+
}
|
|
377
433
|
}
|
|
378
434
|
|
|
379
435
|
/**
|
|
@@ -396,7 +452,8 @@ class BaseGemini {
|
|
|
396
452
|
modelVersion: meta.modelVersion,
|
|
397
453
|
requestedModel: meta.requestedModel,
|
|
398
454
|
timestamp: meta.timestamp,
|
|
399
|
-
groundingMetadata: meta.groundingMetadata || null
|
|
455
|
+
groundingMetadata: meta.groundingMetadata || null,
|
|
456
|
+
modelStatus: meta.modelStatus || null
|
|
400
457
|
};
|
|
401
458
|
}
|
|
402
459
|
|
package/chat.js
CHANGED
|
@@ -47,6 +47,19 @@ class Chat extends BaseGemini {
|
|
|
47
47
|
log.debug(`Chat created with model: ${this.modelName}`);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Seeds the conversation with example pairs stored as plain prose turns.
|
|
52
|
+
* Chat is a prose agent — model turns are stored verbatim, not wrapped in
|
|
53
|
+
* Transformer's {data} JSON envelope.
|
|
54
|
+
*
|
|
55
|
+
* @param {import('./types').TransformationExample[]} [examples]
|
|
56
|
+
* @param {import('./types').SeedOptions} [opts={}]
|
|
57
|
+
* @returns {Promise<Array>} The updated chat history
|
|
58
|
+
*/
|
|
59
|
+
async seed(examples, opts = {}) {
|
|
60
|
+
return super.seed(examples, { format: 'text', ...opts });
|
|
61
|
+
}
|
|
62
|
+
|
|
50
63
|
/**
|
|
51
64
|
* Send a text message and get a response. Adds to conversation history.
|
|
52
65
|
*
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview ImageGenerator — Generate images via Gemini's Nano Banana models.
|
|
3
|
+
*
|
|
4
|
+
* Extends BaseGemini for auth/client reuse but overrides init() to skip chat session
|
|
5
|
+
* creation (image gen is stateless). Mirrors the Embedding class pattern.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```javascript
|
|
9
|
+
* import { ImageGenerator } from 'ak-gemini';
|
|
10
|
+
* import { writeFileSync } from 'node:fs';
|
|
11
|
+
*
|
|
12
|
+
* const gen = new ImageGenerator({ apiKey: 'your-key' });
|
|
13
|
+
* const result = await gen.generate('A cat astronaut on the moon');
|
|
14
|
+
* writeFileSync('cat.png', Buffer.from(result.images[0].data, 'base64'));
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import BaseGemini from './base.js';
|
|
19
|
+
import log from './logger.js';
|
|
20
|
+
import { writeFileSync } from 'node:fs';
|
|
21
|
+
|
|
22
|
+
const DEFAULT_IMAGE_MODEL = 'gemini-3.1-flash-image-preview';
|
|
23
|
+
|
|
24
|
+
export default class ImageGenerator extends BaseGemini {
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {import('./types.d.ts').ImageGeneratorOptions} [options={}]
|
|
28
|
+
*/
|
|
29
|
+
constructor(options = {}) {
|
|
30
|
+
if (options.modelName === undefined) {
|
|
31
|
+
options = { ...options, modelName: DEFAULT_IMAGE_MODEL };
|
|
32
|
+
}
|
|
33
|
+
if (options.systemPrompt === undefined) {
|
|
34
|
+
options = { ...options, systemPrompt: null };
|
|
35
|
+
}
|
|
36
|
+
super(options);
|
|
37
|
+
|
|
38
|
+
this.aspectRatio = options.aspectRatio || null;
|
|
39
|
+
this.imageSize = options.imageSize || null;
|
|
40
|
+
this.personGeneration = options.personGeneration || null;
|
|
41
|
+
this.includeText = options.includeText ?? false;
|
|
42
|
+
|
|
43
|
+
log.debug(`ImageGenerator created with model: ${this.modelName}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Validate API connection only; no chat session (stateless).
|
|
48
|
+
* @param {boolean} [force=false]
|
|
49
|
+
*/
|
|
50
|
+
async init(force = false) {
|
|
51
|
+
if (this._initialized && !force) return;
|
|
52
|
+
|
|
53
|
+
log.debug(`Initializing ${this.constructor.name} with model: ${this.modelName}...`);
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
await this.genAIClient.models.list();
|
|
57
|
+
log.debug(`${this.constructor.name}: API connection successful.`);
|
|
58
|
+
} catch (e) {
|
|
59
|
+
throw new Error(`${this.constructor.name} initialization failed: ${e.message}`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
this._initialized = true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Build a FRESH config — Gemini image models reject safetySettings/temp/topK/topP/thinkingConfig.
|
|
67
|
+
* Do NOT spread this.chatConfig.
|
|
68
|
+
* @private
|
|
69
|
+
*/
|
|
70
|
+
_buildConfig(overrides = {}) {
|
|
71
|
+
const includeText = overrides.includeText ?? this.includeText;
|
|
72
|
+
const config = { responseModalities: includeText ? ['IMAGE', 'TEXT'] : ['IMAGE'] };
|
|
73
|
+
|
|
74
|
+
const imageConfig = {};
|
|
75
|
+
const aspectRatio = overrides.aspectRatio || this.aspectRatio;
|
|
76
|
+
const imageSize = overrides.imageSize || this.imageSize;
|
|
77
|
+
const personGeneration = overrides.personGeneration || this.personGeneration;
|
|
78
|
+
if (aspectRatio) imageConfig.aspectRatio = aspectRatio;
|
|
79
|
+
if (imageSize) imageConfig.imageSize = imageSize;
|
|
80
|
+
if (personGeneration) imageConfig.personGeneration = personGeneration;
|
|
81
|
+
if (Object.keys(imageConfig).length > 0) config.imageConfig = imageConfig;
|
|
82
|
+
|
|
83
|
+
return config;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Generate one or more images from a text prompt.
|
|
88
|
+
* Optionally accepts `inputImages` for image editing / multi-image composition.
|
|
89
|
+
*
|
|
90
|
+
* @param {string} prompt
|
|
91
|
+
* @param {import('./types.d.ts').ImageGenerateOptions} [opts={}]
|
|
92
|
+
* @returns {Promise<import('./types.d.ts').ImageGenerationResult>}
|
|
93
|
+
*/
|
|
94
|
+
async generate(prompt, opts = {}) {
|
|
95
|
+
if (!this._initialized) await this.init();
|
|
96
|
+
|
|
97
|
+
/** @type {any[]} */
|
|
98
|
+
const parts = [{ text: prompt }];
|
|
99
|
+
if (Array.isArray(opts.inputImages)) {
|
|
100
|
+
for (const img of opts.inputImages) {
|
|
101
|
+
parts.push({ inlineData: { data: img.data, mimeType: img.mimeType } });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const result = await this._withRetry(() => this.genAIClient.models.generateContent({
|
|
106
|
+
model: this.modelName,
|
|
107
|
+
contents: [{ role: 'user', parts }],
|
|
108
|
+
config: this._buildConfig(opts)
|
|
109
|
+
}));
|
|
110
|
+
|
|
111
|
+
this._captureMetadata(result);
|
|
112
|
+
this._cumulativeUsage = {
|
|
113
|
+
promptTokens: this.lastResponseMetadata.promptTokens,
|
|
114
|
+
responseTokens: this.lastResponseMetadata.responseTokens,
|
|
115
|
+
totalTokens: this.lastResponseMetadata.totalTokens,
|
|
116
|
+
attempts: 1
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const images = [];
|
|
120
|
+
let text = '';
|
|
121
|
+
const responseParts = result.candidates?.[0]?.content?.parts || [];
|
|
122
|
+
for (const part of responseParts) {
|
|
123
|
+
if (part.inlineData?.data) {
|
|
124
|
+
images.push({
|
|
125
|
+
data: part.inlineData.data,
|
|
126
|
+
mimeType: part.inlineData.mimeType || 'image/png'
|
|
127
|
+
});
|
|
128
|
+
} else if (part.text) {
|
|
129
|
+
text += part.text;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (images.length === 0) {
|
|
134
|
+
log.warn('ImageGenerator: no images returned. Check prompt or safety filters.');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return { images, text: text || null, usage: this.getLastUsage() };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Convenience: write one or all images to disk.
|
|
142
|
+
* If multiple images, suffixes with `_N` before extension.
|
|
143
|
+
* @param {import('./types.d.ts').ImageGenerationResult} result
|
|
144
|
+
* @param {string} filePath
|
|
145
|
+
* @returns {string[]} Written file paths
|
|
146
|
+
*/
|
|
147
|
+
save(result, filePath) {
|
|
148
|
+
if (!result?.images?.length) {
|
|
149
|
+
log.warn('ImageGenerator.save(): no images to save.');
|
|
150
|
+
return [];
|
|
151
|
+
}
|
|
152
|
+
const paths = [];
|
|
153
|
+
const dot = filePath.lastIndexOf('.');
|
|
154
|
+
const base = dot >= 0 ? filePath.slice(0, dot) : filePath;
|
|
155
|
+
const ext = dot >= 0 ? filePath.slice(dot) : '.png';
|
|
156
|
+
result.images.forEach((img, i) => {
|
|
157
|
+
const out = result.images.length === 1 ? filePath : `${base}_${i}${ext}`;
|
|
158
|
+
writeFileSync(out, Buffer.from(img.data, 'base64'));
|
|
159
|
+
paths.push(out);
|
|
160
|
+
});
|
|
161
|
+
return paths;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ── No-ops (image gen is stateless) ──
|
|
165
|
+
|
|
166
|
+
/** @returns {any[]} Always returns empty array */
|
|
167
|
+
getHistory() { return []; }
|
|
168
|
+
|
|
169
|
+
/** No-op for ImageGenerator */
|
|
170
|
+
async clearHistory() {}
|
|
171
|
+
|
|
172
|
+
/** No-op for ImageGenerator */
|
|
173
|
+
async seed() {
|
|
174
|
+
log.warn('ImageGenerator.seed() is a no-op — image generation does not support few-shot.');
|
|
175
|
+
return [];
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* @param {any} _nextPayload
|
|
180
|
+
* @throws {Error} ImageGenerator does not support token estimation
|
|
181
|
+
* @returns {Promise<{ inputTokens: number }>}
|
|
182
|
+
*/
|
|
183
|
+
async estimate(_nextPayload) {
|
|
184
|
+
throw new Error('ImageGenerator does not support token estimation. Use generate() directly.');
|
|
185
|
+
}
|
|
186
|
+
}
|
package/index.cjs
CHANGED
|
@@ -35,6 +35,7 @@ __export(index_exports, {
|
|
|
35
35
|
Embedding: () => Embedding,
|
|
36
36
|
HarmBlockThreshold: () => import_genai2.HarmBlockThreshold,
|
|
37
37
|
HarmCategory: () => import_genai2.HarmCategory,
|
|
38
|
+
ImageGenerator: () => ImageGenerator,
|
|
38
39
|
Message: () => message_default,
|
|
39
40
|
RagAgent: () => rag_agent_default,
|
|
40
41
|
ThinkingLevel: () => import_genai2.ThinkingLevel,
|
|
@@ -322,29 +323,48 @@ var DEFAULT_THINKING_CONFIG = {
|
|
|
322
323
|
};
|
|
323
324
|
var DEFAULT_MAX_OUTPUT_TOKENS = 5e4;
|
|
324
325
|
var THINKING_SUPPORTED_MODELS = [
|
|
325
|
-
/^gemini-3
|
|
326
|
-
/^gemini-3
|
|
326
|
+
/^gemini-3(\.\d+)?-pro(-preview)?$/,
|
|
327
|
+
/^gemini-3(\.\d+)?-flash(-preview)?$/,
|
|
328
|
+
/^gemini-3(\.\d+)?-flash-lite(-preview)?$/,
|
|
327
329
|
/^gemini-2\.5-pro/,
|
|
328
330
|
/^gemini-2\.5-flash(-preview)?$/,
|
|
329
331
|
/^gemini-2\.5-flash-lite(-preview)?$/,
|
|
330
332
|
/^gemini-2\.0-flash$/
|
|
331
333
|
];
|
|
332
334
|
var MODEL_PRICING = {
|
|
333
|
-
|
|
334
|
-
"gemini-
|
|
335
|
-
"gemini-
|
|
336
|
-
|
|
335
|
+
// Gemini 3.x stable
|
|
336
|
+
"gemini-3.5-flash": { input: 1.5, output: 9 },
|
|
337
|
+
"gemini-3.1-flash-lite": { input: 0.25, output: 1.5 },
|
|
338
|
+
// Gemini 3.x preview
|
|
339
|
+
"gemini-3.1-pro-preview": { input: 2, output: 12 },
|
|
340
|
+
// ≤200k tier
|
|
337
341
|
"gemini-3-pro-preview": { input: 2, output: 12 },
|
|
342
|
+
// ≤200k tier; launch rate (superseded by 3.1, off the pricing page)
|
|
343
|
+
"gemini-3-flash-preview": { input: 0.5, output: 3 },
|
|
344
|
+
"gemini-3.1-flash-lite-preview": { input: 0.25, output: 1.5 },
|
|
345
|
+
"gemini-3.1-flash-image-preview": { input: 0.5, output: 3 },
|
|
346
|
+
// text-only; image-output is $60/M
|
|
347
|
+
"gemini-3-pro-image-preview": { input: 2, output: 12 },
|
|
348
|
+
// text-only; image-output is $120/M
|
|
349
|
+
// Gemini 2.5 stable
|
|
350
|
+
"gemini-2.5-flash": { input: 0.3, output: 2.5 },
|
|
351
|
+
"gemini-2.5-flash-lite": { input: 0.1, output: 0.4 },
|
|
352
|
+
"gemini-2.5-pro": { input: 1.25, output: 10 },
|
|
353
|
+
// ≤200k tier
|
|
354
|
+
"gemini-2.5-flash-image": { input: 0.3, output: 0 },
|
|
355
|
+
// image-output is ~$0.039/image (1290 tokens)
|
|
356
|
+
// Deprecated but kept for back-compat (shut down June 2026)
|
|
338
357
|
"gemini-2.0-flash": { input: 0.1, output: 0.4 },
|
|
339
358
|
"gemini-2.0-flash-lite": { input: 0.02, output: 0.1 },
|
|
340
|
-
|
|
359
|
+
// Embeddings
|
|
360
|
+
"gemini-embedding-001": { input: 0.15, output: 0 }
|
|
341
361
|
};
|
|
342
362
|
var BaseGemini = class {
|
|
343
363
|
/**
|
|
344
364
|
* @param {BaseGeminiOptions} [options={}]
|
|
345
365
|
*/
|
|
346
366
|
constructor(options = {}) {
|
|
347
|
-
this.modelName = options.modelName || "gemini-
|
|
367
|
+
this.modelName = options.modelName || "gemini-3-flash-preview";
|
|
348
368
|
if (options.systemPrompt !== void 0) {
|
|
349
369
|
this.systemPrompt = options.systemPrompt;
|
|
350
370
|
} else {
|
|
@@ -369,6 +389,8 @@ var BaseGemini = class {
|
|
|
369
389
|
this.enableGrounding = options.enableGrounding || false;
|
|
370
390
|
this.groundingConfig = options.groundingConfig || {};
|
|
371
391
|
this.cachedContent = options.cachedContent || null;
|
|
392
|
+
this.serviceTier = options.serviceTier || null;
|
|
393
|
+
this.includeServerSideToolInvocations = options.includeServerSideToolInvocations ?? false;
|
|
372
394
|
this.chatConfig = {
|
|
373
395
|
temperature: 0.7,
|
|
374
396
|
topP: 0.95,
|
|
@@ -376,6 +398,11 @@ var BaseGemini = class {
|
|
|
376
398
|
safetySettings: DEFAULT_SAFETY_SETTINGS,
|
|
377
399
|
...options.chatConfig
|
|
378
400
|
};
|
|
401
|
+
if (this.serviceTier) this.chatConfig["serviceTier"] = this.serviceTier;
|
|
402
|
+
if (this.includeServerSideToolInvocations) this.chatConfig["includeServerSideToolInvocations"] = true;
|
|
403
|
+
for (const key of ["temperature", "topP", "topK"]) {
|
|
404
|
+
if (options[key] !== void 0) this.chatConfig[key] = options[key];
|
|
405
|
+
}
|
|
379
406
|
if (this.systemPrompt) {
|
|
380
407
|
this.chatConfig.systemInstruction = this.systemPrompt;
|
|
381
408
|
} else if (this.systemPrompt === null && options.systemPrompt === void 0) {
|
|
@@ -509,6 +536,7 @@ var BaseGemini = class {
|
|
|
509
536
|
* @param {string} [opts.contextKey='CONTEXT'] - Key for optional context
|
|
510
537
|
* @param {string} [opts.explanationKey='EXPLANATION'] - Key for optional explanations
|
|
511
538
|
* @param {string} [opts.systemPromptKey='SYSTEM'] - Key for system prompt overrides in examples
|
|
539
|
+
* @param {'json'|'text'} [opts.format='json'] - Model-turn format: 'json' wraps answers in a {data} envelope (Transformer protocol); 'text' stores ANSWER verbatim (prose agents like Chat)
|
|
512
540
|
* @returns {Promise<Array>} The updated chat history
|
|
513
541
|
*/
|
|
514
542
|
async seed(examples, opts = {}) {
|
|
@@ -522,6 +550,7 @@ var BaseGemini = class {
|
|
|
522
550
|
const contextKey = opts.contextKey || "CONTEXT";
|
|
523
551
|
const explanationKey = opts.explanationKey || "EXPLANATION";
|
|
524
552
|
const systemPromptKey = opts.systemPromptKey || "SYSTEM";
|
|
553
|
+
const format = opts.format || "json";
|
|
525
554
|
const instructionExample = examples.find((ex) => ex[systemPromptKey]);
|
|
526
555
|
if (instructionExample) {
|
|
527
556
|
logger_default.debug(`Found system prompt in examples; reinitializing chat.`);
|
|
@@ -550,9 +579,15 @@ ${contextText}
|
|
|
550
579
|
let promptText = isJSON(promptValue) ? JSON.stringify(promptValue, null, 2) : promptValue;
|
|
551
580
|
userText += promptText;
|
|
552
581
|
}
|
|
553
|
-
|
|
554
|
-
if (
|
|
555
|
-
|
|
582
|
+
let modelText;
|
|
583
|
+
if (format === "text") {
|
|
584
|
+
modelText = isJSON(answerValue) ? JSON.stringify(answerValue, null, 2) : String(answerValue || "");
|
|
585
|
+
if (explanationValue) logger_default.warn("seed(): EXPLANATION has no representation in text format; ignored.");
|
|
586
|
+
} else {
|
|
587
|
+
if (answerValue) modelResponse.data = answerValue;
|
|
588
|
+
if (explanationValue) modelResponse.explanation = explanationValue;
|
|
589
|
+
modelText = JSON.stringify(modelResponse, null, 2);
|
|
590
|
+
}
|
|
556
591
|
if (userText.trim().length && modelText.trim().length > 0) {
|
|
557
592
|
historyToAdd.push({ role: "user", parts: [{ text: userText.trim() }] });
|
|
558
593
|
historyToAdd.push({ role: "model", parts: [{ text: modelText.trim() }] });
|
|
@@ -573,6 +608,7 @@ ${contextText}
|
|
|
573
608
|
* @protected
|
|
574
609
|
*/
|
|
575
610
|
_captureMetadata(response) {
|
|
611
|
+
const modelStatus = response?.modelStatus || null;
|
|
576
612
|
this.lastResponseMetadata = {
|
|
577
613
|
modelVersion: response.modelVersion || null,
|
|
578
614
|
requestedModel: this.modelName,
|
|
@@ -580,8 +616,13 @@ ${contextText}
|
|
|
580
616
|
responseTokens: response.usageMetadata?.candidatesTokenCount || 0,
|
|
581
617
|
totalTokens: response.usageMetadata?.totalTokenCount || 0,
|
|
582
618
|
timestamp: Date.now(),
|
|
583
|
-
groundingMetadata: response.candidates?.[0]?.groundingMetadata || null
|
|
619
|
+
groundingMetadata: response.candidates?.[0]?.groundingMetadata || null,
|
|
620
|
+
modelStatus
|
|
584
621
|
};
|
|
622
|
+
if (modelStatus === "DEPRECATED" && !this._deprecationWarned) {
|
|
623
|
+
logger_default.warn(`Model "${this.modelName}" is marked DEPRECATED by Google. Plan migration.`);
|
|
624
|
+
this._deprecationWarned = true;
|
|
625
|
+
}
|
|
585
626
|
}
|
|
586
627
|
/**
|
|
587
628
|
* Returns structured usage data from the last API call for billing verification.
|
|
@@ -601,7 +642,8 @@ ${contextText}
|
|
|
601
642
|
modelVersion: meta.modelVersion,
|
|
602
643
|
requestedModel: meta.requestedModel,
|
|
603
644
|
timestamp: meta.timestamp,
|
|
604
|
-
groundingMetadata: meta.groundingMetadata || null
|
|
645
|
+
groundingMetadata: meta.groundingMetadata || null,
|
|
646
|
+
modelStatus: meta.modelStatus || null
|
|
605
647
|
};
|
|
606
648
|
}
|
|
607
649
|
// ── Token Estimation ─────────────────────────────────────────────────────
|
|
@@ -909,7 +951,8 @@ var Transformer = class extends base_default {
|
|
|
909
951
|
answerKey: this.answerKey,
|
|
910
952
|
contextKey: this.contextKey,
|
|
911
953
|
explanationKey: this.explanationKey,
|
|
912
|
-
systemPromptKey: this.systemPromptKey
|
|
954
|
+
systemPromptKey: this.systemPromptKey,
|
|
955
|
+
format: "json"
|
|
913
956
|
});
|
|
914
957
|
}
|
|
915
958
|
// ── Primary Send Method ──────────────────────────────────────────────────
|
|
@@ -1187,6 +1230,18 @@ var Chat = class extends base_default {
|
|
|
1187
1230
|
super(options);
|
|
1188
1231
|
logger_default.debug(`Chat created with model: ${this.modelName}`);
|
|
1189
1232
|
}
|
|
1233
|
+
/**
|
|
1234
|
+
* Seeds the conversation with example pairs stored as plain prose turns.
|
|
1235
|
+
* Chat is a prose agent — model turns are stored verbatim, not wrapped in
|
|
1236
|
+
* Transformer's {data} JSON envelope.
|
|
1237
|
+
*
|
|
1238
|
+
* @param {import('./types').TransformationExample[]} [examples]
|
|
1239
|
+
* @param {import('./types').SeedOptions} [opts={}]
|
|
1240
|
+
* @returns {Promise<Array>} The updated chat history
|
|
1241
|
+
*/
|
|
1242
|
+
async seed(examples, opts = {}) {
|
|
1243
|
+
return super.seed(examples, { format: "text", ...opts });
|
|
1244
|
+
}
|
|
1190
1245
|
/**
|
|
1191
1246
|
* Send a text message and get a response. Adds to conversation history.
|
|
1192
1247
|
*
|
|
@@ -3035,9 +3090,155 @@ var Embedding = class extends base_default {
|
|
|
3035
3090
|
}
|
|
3036
3091
|
};
|
|
3037
3092
|
|
|
3093
|
+
// image-generator.js
|
|
3094
|
+
var import_node_fs = require("node:fs");
|
|
3095
|
+
var DEFAULT_IMAGE_MODEL = "gemini-3.1-flash-image-preview";
|
|
3096
|
+
var ImageGenerator = class extends base_default {
|
|
3097
|
+
/**
|
|
3098
|
+
* @param {import('./types.d.ts').ImageGeneratorOptions} [options={}]
|
|
3099
|
+
*/
|
|
3100
|
+
constructor(options = {}) {
|
|
3101
|
+
if (options.modelName === void 0) {
|
|
3102
|
+
options = { ...options, modelName: DEFAULT_IMAGE_MODEL };
|
|
3103
|
+
}
|
|
3104
|
+
if (options.systemPrompt === void 0) {
|
|
3105
|
+
options = { ...options, systemPrompt: null };
|
|
3106
|
+
}
|
|
3107
|
+
super(options);
|
|
3108
|
+
this.aspectRatio = options.aspectRatio || null;
|
|
3109
|
+
this.imageSize = options.imageSize || null;
|
|
3110
|
+
this.personGeneration = options.personGeneration || null;
|
|
3111
|
+
this.includeText = options.includeText ?? false;
|
|
3112
|
+
logger_default.debug(`ImageGenerator created with model: ${this.modelName}`);
|
|
3113
|
+
}
|
|
3114
|
+
/**
|
|
3115
|
+
* Validate API connection only; no chat session (stateless).
|
|
3116
|
+
* @param {boolean} [force=false]
|
|
3117
|
+
*/
|
|
3118
|
+
async init(force = false) {
|
|
3119
|
+
if (this._initialized && !force) return;
|
|
3120
|
+
logger_default.debug(`Initializing ${this.constructor.name} with model: ${this.modelName}...`);
|
|
3121
|
+
try {
|
|
3122
|
+
await this.genAIClient.models.list();
|
|
3123
|
+
logger_default.debug(`${this.constructor.name}: API connection successful.`);
|
|
3124
|
+
} catch (e) {
|
|
3125
|
+
throw new Error(`${this.constructor.name} initialization failed: ${e.message}`);
|
|
3126
|
+
}
|
|
3127
|
+
this._initialized = true;
|
|
3128
|
+
}
|
|
3129
|
+
/**
|
|
3130
|
+
* Build a FRESH config — Gemini image models reject safetySettings/temp/topK/topP/thinkingConfig.
|
|
3131
|
+
* Do NOT spread this.chatConfig.
|
|
3132
|
+
* @private
|
|
3133
|
+
*/
|
|
3134
|
+
_buildConfig(overrides = {}) {
|
|
3135
|
+
const includeText = overrides.includeText ?? this.includeText;
|
|
3136
|
+
const config = { responseModalities: includeText ? ["IMAGE", "TEXT"] : ["IMAGE"] };
|
|
3137
|
+
const imageConfig = {};
|
|
3138
|
+
const aspectRatio = overrides.aspectRatio || this.aspectRatio;
|
|
3139
|
+
const imageSize = overrides.imageSize || this.imageSize;
|
|
3140
|
+
const personGeneration = overrides.personGeneration || this.personGeneration;
|
|
3141
|
+
if (aspectRatio) imageConfig.aspectRatio = aspectRatio;
|
|
3142
|
+
if (imageSize) imageConfig.imageSize = imageSize;
|
|
3143
|
+
if (personGeneration) imageConfig.personGeneration = personGeneration;
|
|
3144
|
+
if (Object.keys(imageConfig).length > 0) config.imageConfig = imageConfig;
|
|
3145
|
+
return config;
|
|
3146
|
+
}
|
|
3147
|
+
/**
|
|
3148
|
+
* Generate one or more images from a text prompt.
|
|
3149
|
+
* Optionally accepts `inputImages` for image editing / multi-image composition.
|
|
3150
|
+
*
|
|
3151
|
+
* @param {string} prompt
|
|
3152
|
+
* @param {import('./types.d.ts').ImageGenerateOptions} [opts={}]
|
|
3153
|
+
* @returns {Promise<import('./types.d.ts').ImageGenerationResult>}
|
|
3154
|
+
*/
|
|
3155
|
+
async generate(prompt, opts = {}) {
|
|
3156
|
+
if (!this._initialized) await this.init();
|
|
3157
|
+
const parts = [{ text: prompt }];
|
|
3158
|
+
if (Array.isArray(opts.inputImages)) {
|
|
3159
|
+
for (const img of opts.inputImages) {
|
|
3160
|
+
parts.push({ inlineData: { data: img.data, mimeType: img.mimeType } });
|
|
3161
|
+
}
|
|
3162
|
+
}
|
|
3163
|
+
const result = await this._withRetry(() => this.genAIClient.models.generateContent({
|
|
3164
|
+
model: this.modelName,
|
|
3165
|
+
contents: [{ role: "user", parts }],
|
|
3166
|
+
config: this._buildConfig(opts)
|
|
3167
|
+
}));
|
|
3168
|
+
this._captureMetadata(result);
|
|
3169
|
+
this._cumulativeUsage = {
|
|
3170
|
+
promptTokens: this.lastResponseMetadata.promptTokens,
|
|
3171
|
+
responseTokens: this.lastResponseMetadata.responseTokens,
|
|
3172
|
+
totalTokens: this.lastResponseMetadata.totalTokens,
|
|
3173
|
+
attempts: 1
|
|
3174
|
+
};
|
|
3175
|
+
const images = [];
|
|
3176
|
+
let text = "";
|
|
3177
|
+
const responseParts = result.candidates?.[0]?.content?.parts || [];
|
|
3178
|
+
for (const part of responseParts) {
|
|
3179
|
+
if (part.inlineData?.data) {
|
|
3180
|
+
images.push({
|
|
3181
|
+
data: part.inlineData.data,
|
|
3182
|
+
mimeType: part.inlineData.mimeType || "image/png"
|
|
3183
|
+
});
|
|
3184
|
+
} else if (part.text) {
|
|
3185
|
+
text += part.text;
|
|
3186
|
+
}
|
|
3187
|
+
}
|
|
3188
|
+
if (images.length === 0) {
|
|
3189
|
+
logger_default.warn("ImageGenerator: no images returned. Check prompt or safety filters.");
|
|
3190
|
+
}
|
|
3191
|
+
return { images, text: text || null, usage: this.getLastUsage() };
|
|
3192
|
+
}
|
|
3193
|
+
/**
|
|
3194
|
+
* Convenience: write one or all images to disk.
|
|
3195
|
+
* If multiple images, suffixes with `_N` before extension.
|
|
3196
|
+
* @param {import('./types.d.ts').ImageGenerationResult} result
|
|
3197
|
+
* @param {string} filePath
|
|
3198
|
+
* @returns {string[]} Written file paths
|
|
3199
|
+
*/
|
|
3200
|
+
save(result, filePath) {
|
|
3201
|
+
if (!result?.images?.length) {
|
|
3202
|
+
logger_default.warn("ImageGenerator.save(): no images to save.");
|
|
3203
|
+
return [];
|
|
3204
|
+
}
|
|
3205
|
+
const paths = [];
|
|
3206
|
+
const dot = filePath.lastIndexOf(".");
|
|
3207
|
+
const base = dot >= 0 ? filePath.slice(0, dot) : filePath;
|
|
3208
|
+
const ext = dot >= 0 ? filePath.slice(dot) : ".png";
|
|
3209
|
+
result.images.forEach((img, i) => {
|
|
3210
|
+
const out = result.images.length === 1 ? filePath : `${base}_${i}${ext}`;
|
|
3211
|
+
(0, import_node_fs.writeFileSync)(out, Buffer.from(img.data, "base64"));
|
|
3212
|
+
paths.push(out);
|
|
3213
|
+
});
|
|
3214
|
+
return paths;
|
|
3215
|
+
}
|
|
3216
|
+
// ── No-ops (image gen is stateless) ──
|
|
3217
|
+
/** @returns {any[]} Always returns empty array */
|
|
3218
|
+
getHistory() {
|
|
3219
|
+
return [];
|
|
3220
|
+
}
|
|
3221
|
+
/** No-op for ImageGenerator */
|
|
3222
|
+
async clearHistory() {
|
|
3223
|
+
}
|
|
3224
|
+
/** No-op for ImageGenerator */
|
|
3225
|
+
async seed() {
|
|
3226
|
+
logger_default.warn("ImageGenerator.seed() is a no-op \u2014 image generation does not support few-shot.");
|
|
3227
|
+
return [];
|
|
3228
|
+
}
|
|
3229
|
+
/**
|
|
3230
|
+
* @param {any} _nextPayload
|
|
3231
|
+
* @throws {Error} ImageGenerator does not support token estimation
|
|
3232
|
+
* @returns {Promise<{ inputTokens: number }>}
|
|
3233
|
+
*/
|
|
3234
|
+
async estimate(_nextPayload) {
|
|
3235
|
+
throw new Error("ImageGenerator does not support token estimation. Use generate() directly.");
|
|
3236
|
+
}
|
|
3237
|
+
};
|
|
3238
|
+
|
|
3038
3239
|
// index.js
|
|
3039
3240
|
var import_genai2 = require("@google/genai");
|
|
3040
|
-
var index_default = { Transformer: transformer_default, Chat: chat_default, Message: message_default, ToolAgent: tool_agent_default, CodeAgent: code_agent_default, RagAgent: rag_agent_default, Embedding };
|
|
3241
|
+
var index_default = { Transformer: transformer_default, Chat: chat_default, Message: message_default, ToolAgent: tool_agent_default, CodeAgent: code_agent_default, RagAgent: rag_agent_default, Embedding, ImageGenerator };
|
|
3041
3242
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3042
3243
|
0 && (module.exports = {
|
|
3043
3244
|
BaseGemini,
|
|
@@ -3046,6 +3247,7 @@ var index_default = { Transformer: transformer_default, Chat: chat_default, Mess
|
|
|
3046
3247
|
Embedding,
|
|
3047
3248
|
HarmBlockThreshold,
|
|
3048
3249
|
HarmCategory,
|
|
3250
|
+
ImageGenerator,
|
|
3049
3251
|
Message,
|
|
3050
3252
|
RagAgent,
|
|
3051
3253
|
ThinkingLevel,
|
package/index.js
CHANGED
|
@@ -27,6 +27,7 @@ export { default as ToolAgent } from './tool-agent.js';
|
|
|
27
27
|
export { default as CodeAgent } from './code-agent.js';
|
|
28
28
|
export { default as RagAgent } from './rag-agent.js';
|
|
29
29
|
export { default as Embedding } from './embedding.js';
|
|
30
|
+
export { default as ImageGenerator } from './image-generator.js';
|
|
30
31
|
export { default as BaseGemini } from './base.js';
|
|
31
32
|
export { default as log } from './logger.js';
|
|
32
33
|
export { ThinkingLevel, HarmCategory, HarmBlockThreshold } from '@google/genai';
|
|
@@ -41,5 +42,6 @@ import ToolAgent from './tool-agent.js';
|
|
|
41
42
|
import CodeAgent from './code-agent.js';
|
|
42
43
|
import RagAgent from './rag-agent.js';
|
|
43
44
|
import Embedding from './embedding.js';
|
|
45
|
+
import ImageGenerator from './image-generator.js';
|
|
44
46
|
|
|
45
|
-
export default { Transformer, Chat, Message, ToolAgent, CodeAgent, RagAgent, Embedding };
|
|
47
|
+
export default { Transformer, Chat, Message, ToolAgent, CodeAgent, RagAgent, Embedding, ImageGenerator };
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "ak-gemini",
|
|
3
3
|
"author": "ak@mixpanel.com",
|
|
4
4
|
"description": "AK's Generative AI Helper for doing... everything",
|
|
5
|
-
"version": "2.
|
|
5
|
+
"version": "2.4.1",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"files": [
|
|
8
8
|
"index.js",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"code-agent.js",
|
|
16
16
|
"rag-agent.js",
|
|
17
17
|
"embedding.js",
|
|
18
|
+
"image-generator.js",
|
|
18
19
|
"json-helpers.js",
|
|
19
20
|
"types.d.ts",
|
|
20
21
|
"logger.js",
|
|
@@ -64,7 +65,7 @@
|
|
|
64
65
|
],
|
|
65
66
|
"license": "ISC",
|
|
66
67
|
"dependencies": {
|
|
67
|
-
"@google/genai": "^
|
|
68
|
+
"@google/genai": "^2.10.0",
|
|
68
69
|
"dotenv": "^17.3.1",
|
|
69
70
|
"pino": "^10.3.1",
|
|
70
71
|
"pino-pretty": "^13.1.3"
|
package/transformer.js
CHANGED
|
@@ -141,7 +141,8 @@ class Transformer extends BaseGemini {
|
|
|
141
141
|
answerKey: this.answerKey,
|
|
142
142
|
contextKey: this.contextKey,
|
|
143
143
|
explanationKey: this.explanationKey,
|
|
144
|
-
systemPromptKey: this.systemPromptKey
|
|
144
|
+
systemPromptKey: this.systemPromptKey,
|
|
145
|
+
format: 'json'
|
|
145
146
|
});
|
|
146
147
|
}
|
|
147
148
|
|
package/types.d.ts
CHANGED
|
@@ -68,12 +68,14 @@ export interface UsageData {
|
|
|
68
68
|
totalTokens: number;
|
|
69
69
|
/** Number of attempts (1 = first try success, 2+ = retries needed) */
|
|
70
70
|
attempts: number;
|
|
71
|
-
/** Actual model that responded (e.g., 'gemini-
|
|
71
|
+
/** Actual model that responded (e.g., 'gemini-3-flash-preview-001') */
|
|
72
72
|
modelVersion: string | null;
|
|
73
|
-
/** Model you requested (e.g., 'gemini-
|
|
73
|
+
/** Model you requested (e.g., 'gemini-3-flash-preview') */
|
|
74
74
|
requestedModel: string;
|
|
75
75
|
timestamp: number;
|
|
76
76
|
groundingMetadata?: GroundingMetadata | null;
|
|
77
|
+
/** Model lifecycle status from Google (e.g., 'DEPRECATED'). Surfaced from @google/genai 1.47+. */
|
|
78
|
+
modelStatus?: string | null;
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
export interface TransformationExample {
|
|
@@ -130,11 +132,12 @@ export interface CachedContentInfo {
|
|
|
130
132
|
|
|
131
133
|
export type AsyncValidatorFunction = (payload: Record<string, unknown>) => Promise<unknown>;
|
|
132
134
|
export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal' | 'none';
|
|
135
|
+
export type ServiceTier = 'STANDARD' | 'FLEX' | 'PRIORITY';
|
|
133
136
|
|
|
134
137
|
// ── Constructor Options ──────────────────────────────────────────────────────
|
|
135
138
|
|
|
136
139
|
export interface BaseGeminiOptions {
|
|
137
|
-
/** Gemini model to use (default: 'gemini-
|
|
140
|
+
/** Gemini model to use (default: 'gemini-3-flash-preview') */
|
|
138
141
|
modelName?: string;
|
|
139
142
|
/** System prompt for the model (null or false to disable) */
|
|
140
143
|
systemPrompt?: string | null | false;
|
|
@@ -144,6 +147,12 @@ export interface BaseGeminiOptions {
|
|
|
144
147
|
thinkingConfig?: ThinkingConfig | null;
|
|
145
148
|
/** Maximum output tokens (default: 50000, null removes limit) */
|
|
146
149
|
maxOutputTokens?: number | null;
|
|
150
|
+
/** Sampling temperature (shorthand for chatConfig.temperature; wins over chatConfig) */
|
|
151
|
+
temperature?: number;
|
|
152
|
+
/** Nucleus sampling (shorthand for chatConfig.topP; wins over chatConfig) */
|
|
153
|
+
topP?: number;
|
|
154
|
+
/** Top-k sampling (shorthand for chatConfig.topK; wins over chatConfig) */
|
|
155
|
+
topK?: number;
|
|
147
156
|
/** Log level (default: based on NODE_ENV) */
|
|
148
157
|
logLevel?: LogLevel;
|
|
149
158
|
|
|
@@ -177,6 +186,12 @@ export interface BaseGeminiOptions {
|
|
|
177
186
|
|
|
178
187
|
/** Run models.list() health check during init() (default: false) */
|
|
179
188
|
healthCheck?: boolean;
|
|
189
|
+
|
|
190
|
+
/** Service tier for generateContent (STANDARD | FLEX | PRIORITY). @google/genai 1.47+ */
|
|
191
|
+
serviceTier?: ServiceTier;
|
|
192
|
+
|
|
193
|
+
/** Surface server-side tool invocations (e.g. Google Search) in the response. @google/genai 1.46+ */
|
|
194
|
+
includeServerSideToolInvocations?: boolean;
|
|
180
195
|
}
|
|
181
196
|
|
|
182
197
|
export interface TransformerOptions extends BaseGeminiOptions {
|
|
@@ -254,6 +269,48 @@ export interface EmbeddingResult {
|
|
|
254
269
|
statistics?: { tokenCount?: number; truncated?: boolean };
|
|
255
270
|
}
|
|
256
271
|
|
|
272
|
+
// ── ImageGenerator ───────────────────────────────────────────────────────────
|
|
273
|
+
|
|
274
|
+
export type ImageAspectRatio = '1:1' | '2:3' | '3:2' | '3:4' | '4:3' | '9:16' | '16:9' | '21:9';
|
|
275
|
+
export type ImageSize = '1K' | '2K' | '4K';
|
|
276
|
+
export type PersonGeneration = 'ALLOW_ALL' | 'ALLOW_ADULT' | 'ALLOW_NONE';
|
|
277
|
+
|
|
278
|
+
export interface ImageGeneratorOptions extends BaseGeminiOptions {
|
|
279
|
+
/** Default aspect ratio for generated images */
|
|
280
|
+
aspectRatio?: ImageAspectRatio;
|
|
281
|
+
/** Default output resolution (1K/2K/4K) */
|
|
282
|
+
imageSize?: ImageSize;
|
|
283
|
+
/** Default people-generation policy */
|
|
284
|
+
personGeneration?: PersonGeneration;
|
|
285
|
+
/** Include text output alongside images (default: false) */
|
|
286
|
+
includeText?: boolean;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export interface ImageGenerateOptions {
|
|
290
|
+
aspectRatio?: ImageAspectRatio;
|
|
291
|
+
imageSize?: ImageSize;
|
|
292
|
+
personGeneration?: PersonGeneration;
|
|
293
|
+
includeText?: boolean;
|
|
294
|
+
/** Reference images for editing / multi-image composition (base64) */
|
|
295
|
+
inputImages?: Array<{ data: string; mimeType: string }>;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export interface GeneratedImage {
|
|
299
|
+
/** Base64-encoded image data */
|
|
300
|
+
data: string;
|
|
301
|
+
/** MIME type (e.g. "image/png") */
|
|
302
|
+
mimeType: string;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export interface ImageGenerationResult {
|
|
306
|
+
/** One or more generated images */
|
|
307
|
+
images: GeneratedImage[];
|
|
308
|
+
/** Optional text response (only when includeText: true) */
|
|
309
|
+
text: string | null;
|
|
310
|
+
/** Token usage */
|
|
311
|
+
usage: UsageData | null;
|
|
312
|
+
}
|
|
313
|
+
|
|
257
314
|
/** Tool declaration in @google/genai FunctionDeclaration format */
|
|
258
315
|
export interface ToolDeclaration {
|
|
259
316
|
name: string;
|
|
@@ -512,6 +569,8 @@ export interface SeedOptions {
|
|
|
512
569
|
contextKey?: string;
|
|
513
570
|
explanationKey?: string;
|
|
514
571
|
systemPromptKey?: string;
|
|
572
|
+
/** Model-turn format: 'json' wraps answers in a {data} envelope (Transformer protocol); 'text' stores ANSWER verbatim (prose agents like Chat). Default: 'json' */
|
|
573
|
+
format?: 'json' | 'text';
|
|
515
574
|
}
|
|
516
575
|
|
|
517
576
|
// ── Class Declarations ───────────────────────────────────────────────────────
|
|
@@ -531,6 +590,8 @@ export declare class BaseGemini {
|
|
|
531
590
|
enableGrounding: boolean;
|
|
532
591
|
groundingConfig: Record<string, any>;
|
|
533
592
|
cachedContent: string | null;
|
|
593
|
+
serviceTier: ServiceTier | null;
|
|
594
|
+
includeServerSideToolInvocations: boolean;
|
|
534
595
|
|
|
535
596
|
init(force?: boolean): Promise<void>;
|
|
536
597
|
seed(examples?: TransformationExample[], opts?: SeedOptions): Promise<any[]>;
|
|
@@ -677,6 +738,21 @@ export declare class Embedding extends BaseGemini {
|
|
|
677
738
|
similarity(a: number[], b: number[]): number;
|
|
678
739
|
}
|
|
679
740
|
|
|
741
|
+
export declare class ImageGenerator extends BaseGemini {
|
|
742
|
+
constructor(options?: ImageGeneratorOptions);
|
|
743
|
+
|
|
744
|
+
aspectRatio: ImageAspectRatio | null;
|
|
745
|
+
imageSize: ImageSize | null;
|
|
746
|
+
personGeneration: PersonGeneration | null;
|
|
747
|
+
includeText: boolean;
|
|
748
|
+
|
|
749
|
+
init(force?: boolean): Promise<void>;
|
|
750
|
+
/** Generate one or more images from a text prompt. Supports optional reference images for editing. */
|
|
751
|
+
generate(prompt: string, opts?: ImageGenerateOptions): Promise<ImageGenerationResult>;
|
|
752
|
+
/** Write generated images to disk (suffixes `_N` before extension if >1 image) */
|
|
753
|
+
save(result: ImageGenerationResult, filePath: string): string[];
|
|
754
|
+
}
|
|
755
|
+
|
|
680
756
|
// ── Module Exports ───────────────────────────────────────────────────────────
|
|
681
757
|
|
|
682
758
|
export declare function extractJSON(text: string): any;
|
|
@@ -690,6 +766,7 @@ declare const _default: {
|
|
|
690
766
|
CodeAgent: typeof CodeAgent;
|
|
691
767
|
RagAgent: typeof RagAgent;
|
|
692
768
|
Embedding: typeof Embedding;
|
|
769
|
+
ImageGenerator: typeof ImageGenerator;
|
|
693
770
|
};
|
|
694
771
|
|
|
695
772
|
export default _default;
|