ak-gemini 1.0.8 → 1.0.10

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.
Files changed (4) hide show
  1. package/index.cjs +68 -4
  2. package/index.js +107 -5
  3. package/package.json +1 -1
  4. package/types.d.ts +13 -7
package/index.cjs CHANGED
@@ -29,6 +29,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
29
29
  // index.js
30
30
  var index_exports = {};
31
31
  __export(index_exports, {
32
+ HarmBlockThreshold: () => import_genai.HarmBlockThreshold,
33
+ HarmCategory: () => import_genai.HarmCategory,
32
34
  ThinkingLevel: () => import_genai.ThinkingLevel,
33
35
  attemptJSONRecovery: () => attemptJSONRecovery,
34
36
  default: () => index_default,
@@ -132,6 +134,7 @@ var AITransformer = class {
132
134
  this.transformWithValidation = prepareAndValidateMessage.bind(this);
133
135
  this.estimate = estimateTokenUsage.bind(this);
134
136
  this.estimateTokenUsage = estimateTokenUsage.bind(this);
137
+ this.updateSystemInstructions = updateSystemInstructions.bind(this);
135
138
  }
136
139
  };
137
140
  var index_default = AITransformer;
@@ -221,6 +224,8 @@ function AITransformFactory(options = {}) {
221
224
  this.retryDelay = options.retryDelay || 1e3;
222
225
  this.asyncValidator = options.asyncValidator || null;
223
226
  this.onlyJSON = options.onlyJSON !== void 0 ? options.onlyJSON : true;
227
+ this.enableGrounding = options.enableGrounding || false;
228
+ this.groundingConfig = options.groundingConfig || {};
224
229
  if (this.promptKey === this.answerKey) {
225
230
  throw new Error("Source and target keys cannot be the same. Please provide distinct keys.");
226
231
  }
@@ -228,6 +233,8 @@ function AITransformFactory(options = {}) {
228
233
  logger_default.debug(`Creating AI Transformer with model: ${this.modelName}`);
229
234
  logger_default.debug(`Using keys - Source: "${this.promptKey}", Target: "${this.answerKey}", Context: "${this.contextKey}"`);
230
235
  logger_default.debug(`Max output tokens set to: ${this.chatConfig.maxOutputTokens}`);
236
+ logger_default.debug(`Using API key: ${this.apiKey.substring(0, 10)}...`);
237
+ logger_default.debug(`Grounding ${this.enableGrounding ? "ENABLED" : "DISABLED"} (costs $35/1k queries)`);
231
238
  }
232
239
  const ai = new import_genai.GoogleGenAI({ apiKey: this.apiKey });
233
240
  this.genAIClient = ai;
@@ -236,12 +243,19 @@ function AITransformFactory(options = {}) {
236
243
  async function initChat(force = false) {
237
244
  if (this.chat && !force) return;
238
245
  logger_default.debug(`Initializing Gemini chat session with model: ${this.modelName}...`);
239
- this.chat = await this.genAIClient.chats.create({
246
+ const chatOptions = {
240
247
  model: this.modelName,
241
248
  // @ts-ignore
242
249
  config: this.chatConfig,
243
250
  history: []
244
- });
251
+ };
252
+ if (this.enableGrounding) {
253
+ chatOptions.config.tools = [{
254
+ googleSearch: this.groundingConfig
255
+ }];
256
+ logger_default.debug(`Search grounding ENABLED for this session (WARNING: costs $35/1k queries)`);
257
+ }
258
+ this.chat = await this.genAIClient.chats.create(chatOptions);
245
259
  try {
246
260
  await this.genAIClient.models.list();
247
261
  logger_default.debug("Gemini API connection successful.");
@@ -345,6 +359,32 @@ async function prepareAndValidateMessage(sourcePayload, options = {}, validatorF
345
359
  }
346
360
  const maxRetries = options.maxRetries ?? this.maxRetries;
347
361
  const retryDelay = options.retryDelay ?? this.retryDelay;
362
+ const enableGroundingForMessage = options.enableGrounding ?? this.enableGrounding;
363
+ const groundingConfigForMessage = options.groundingConfig ?? this.groundingConfig;
364
+ if (enableGroundingForMessage !== this.enableGrounding) {
365
+ const originalGrounding = this.enableGrounding;
366
+ const originalConfig = this.groundingConfig;
367
+ try {
368
+ this.enableGrounding = enableGroundingForMessage;
369
+ this.groundingConfig = groundingConfigForMessage;
370
+ await this.init(true);
371
+ if (enableGroundingForMessage) {
372
+ logger_default.warn(`Search grounding ENABLED for this message (WARNING: costs $35/1k queries)`);
373
+ } else {
374
+ logger_default.debug(`Search grounding DISABLED for this message`);
375
+ }
376
+ } catch (error) {
377
+ this.enableGrounding = originalGrounding;
378
+ this.groundingConfig = originalConfig;
379
+ throw error;
380
+ }
381
+ const restoreGrounding = async () => {
382
+ this.enableGrounding = originalGrounding;
383
+ this.groundingConfig = originalConfig;
384
+ await this.init(true);
385
+ };
386
+ options._restoreGrounding = restoreGrounding;
387
+ }
348
388
  let lastError = null;
349
389
  let lastPayload = null;
350
390
  if (sourcePayload && isJSON(sourcePayload)) {
@@ -366,12 +406,18 @@ async function prepareAndValidateMessage(sourcePayload, options = {}, validatorF
366
406
  await validatorFn(transformedPayload);
367
407
  }
368
408
  logger_default.debug(`Transformation succeeded on attempt ${attempt + 1}`);
409
+ if (options._restoreGrounding) {
410
+ await options._restoreGrounding();
411
+ }
369
412
  return transformedPayload;
370
413
  } catch (error) {
371
414
  lastError = error;
372
415
  logger_default.warn(`Attempt ${attempt + 1} failed: ${error.message}`);
373
416
  if (attempt >= maxRetries) {
374
417
  logger_default.error(`All ${maxRetries + 1} attempts failed.`);
418
+ if (options._restoreGrounding) {
419
+ await options._restoreGrounding();
420
+ }
375
421
  throw new Error(`Transformation failed after ${maxRetries + 1} attempts. Last error: ${error.message}`);
376
422
  }
377
423
  const delay = retryDelay * Math.pow(2, attempt);
@@ -430,12 +476,19 @@ async function estimateTokenUsage(nextPayload) {
430
476
  async function resetChat() {
431
477
  if (this.chat) {
432
478
  logger_default.debug("Resetting Gemini chat session...");
433
- this.chat = await this.genAIClient.chats.create({
479
+ const chatOptions = {
434
480
  model: this.modelName,
435
481
  // @ts-ignore
436
482
  config: this.chatConfig,
437
483
  history: []
438
- });
484
+ };
485
+ if (this.enableGrounding) {
486
+ chatOptions.config.tools = [{
487
+ googleSearch: this.groundingConfig
488
+ }];
489
+ logger_default.debug(`Search grounding preserved during reset (WARNING: costs $35/1k queries)`);
490
+ }
491
+ this.chat = await this.genAIClient.chats.create(chatOptions);
439
492
  logger_default.debug("Chat session reset.");
440
493
  } else {
441
494
  logger_default.warn("Cannot reset chat session: chat not yet initialized.");
@@ -448,6 +501,15 @@ function getChatHistory() {
448
501
  }
449
502
  return this.chat.getHistory();
450
503
  }
504
+ async function updateSystemInstructions(newInstructions) {
505
+ if (!newInstructions || typeof newInstructions !== "string") {
506
+ throw new Error("System instructions must be a non-empty string");
507
+ }
508
+ this.systemInstructions = newInstructions.trim();
509
+ this.chatConfig.systemInstruction = this.systemInstructions;
510
+ logger_default.debug("Updating system instructions and reinitializing chat...");
511
+ await this.init(true);
512
+ }
451
513
  function attemptJSONRecovery(text, maxAttempts = 100) {
452
514
  if (!text || typeof text !== "string") return null;
453
515
  try {
@@ -748,6 +810,8 @@ if (import_meta.url === new URL(`file://${process.argv[1]}`).href) {
748
810
  }
749
811
  // Annotate the CommonJS export names for ESM import in node:
750
812
  0 && (module.exports = {
813
+ HarmBlockThreshold,
814
+ HarmCategory,
751
815
  ThinkingLevel,
752
816
  attemptJSONRecovery,
753
817
  log
package/index.js CHANGED
@@ -28,7 +28,7 @@ import u from 'ak-tools';
28
28
  import path from 'path';
29
29
  import log from './logger.js';
30
30
  export { log };
31
- export { ThinkingLevel };
31
+ export { ThinkingLevel, HarmCategory, HarmBlockThreshold };
32
32
 
33
33
 
34
34
 
@@ -134,6 +134,7 @@ class AITransformer {
134
134
  this.transformWithValidation = prepareAndValidateMessage.bind(this);
135
135
  this.estimate = estimateTokenUsage.bind(this);
136
136
  this.estimateTokenUsage = estimateTokenUsage.bind(this);
137
+ this.updateSystemInstructions = updateSystemInstructions.bind(this);
137
138
  }
138
139
  }
139
140
 
@@ -265,6 +266,10 @@ function AITransformFactory(options = {}) {
265
266
  //are we forcing json responses only?
266
267
  this.onlyJSON = options.onlyJSON !== undefined ? options.onlyJSON : true; // If true, only return JSON responses
267
268
 
269
+ // Grounding configuration (disabled by default to avoid costs)
270
+ this.enableGrounding = options.enableGrounding || false;
271
+ this.groundingConfig = options.groundingConfig || {};
272
+
268
273
  if (this.promptKey === this.answerKey) {
269
274
  throw new Error("Source and target keys cannot be the same. Please provide distinct keys.");
270
275
  }
@@ -273,6 +278,9 @@ function AITransformFactory(options = {}) {
273
278
  log.debug(`Creating AI Transformer with model: ${this.modelName}`);
274
279
  log.debug(`Using keys - Source: "${this.promptKey}", Target: "${this.answerKey}", Context: "${this.contextKey}"`);
275
280
  log.debug(`Max output tokens set to: ${this.chatConfig.maxOutputTokens}`);
281
+ // Log API key prefix for tracking (first 10 chars only for security)
282
+ log.debug(`Using API key: ${this.apiKey.substring(0, 10)}...`);
283
+ log.debug(`Grounding ${this.enableGrounding ? 'ENABLED' : 'DISABLED'} (costs $35/1k queries)`);
276
284
  }
277
285
 
278
286
  const ai = new GoogleGenAI({ apiKey: this.apiKey });
@@ -291,12 +299,23 @@ async function initChat(force = false) {
291
299
 
292
300
  log.debug(`Initializing Gemini chat session with model: ${this.modelName}...`);
293
301
 
294
- this.chat = await this.genAIClient.chats.create({
302
+ // Add grounding tools if enabled
303
+ const chatOptions = {
295
304
  model: this.modelName,
296
305
  // @ts-ignore
297
306
  config: this.chatConfig,
298
307
  history: [],
299
- });
308
+ };
309
+
310
+ // Only add tools if grounding is explicitly enabled
311
+ if (this.enableGrounding) {
312
+ chatOptions.config.tools = [{
313
+ googleSearch: this.groundingConfig
314
+ }];
315
+ log.debug(`Search grounding ENABLED for this session (WARNING: costs $35/1k queries)`);
316
+ }
317
+
318
+ this.chat = await this.genAIClient.chats.create(chatOptions);
300
319
 
301
320
  try {
302
321
  await this.genAIClient.models.list();
@@ -463,6 +482,47 @@ async function prepareAndValidateMessage(sourcePayload, options = {}, validatorF
463
482
  const maxRetries = options.maxRetries ?? this.maxRetries;
464
483
  const retryDelay = options.retryDelay ?? this.retryDelay;
465
484
 
485
+ // Check if grounding should be enabled for this specific message
486
+ const enableGroundingForMessage = options.enableGrounding ?? this.enableGrounding;
487
+ const groundingConfigForMessage = options.groundingConfig ?? this.groundingConfig;
488
+
489
+ // Reinitialize chat if grounding settings changed for this message
490
+ if (enableGroundingForMessage !== this.enableGrounding) {
491
+ const originalGrounding = this.enableGrounding;
492
+ const originalConfig = this.groundingConfig;
493
+
494
+ try {
495
+ // Temporarily change grounding settings
496
+ this.enableGrounding = enableGroundingForMessage;
497
+ this.groundingConfig = groundingConfigForMessage;
498
+
499
+ // Force reinit with new settings
500
+ await this.init(true);
501
+
502
+ // Log the change
503
+ if (enableGroundingForMessage) {
504
+ log.warn(`Search grounding ENABLED for this message (WARNING: costs $35/1k queries)`);
505
+ } else {
506
+ log.debug(`Search grounding DISABLED for this message`);
507
+ }
508
+ } catch (error) {
509
+ // Restore original settings on error
510
+ this.enableGrounding = originalGrounding;
511
+ this.groundingConfig = originalConfig;
512
+ throw error;
513
+ }
514
+
515
+ // Schedule restoration after message completes
516
+ const restoreGrounding = async () => {
517
+ this.enableGrounding = originalGrounding;
518
+ this.groundingConfig = originalConfig;
519
+ await this.init(true);
520
+ };
521
+
522
+ // Store restoration function to call after message completes
523
+ options._restoreGrounding = restoreGrounding;
524
+ }
525
+
466
526
  let lastError = null;
467
527
  let lastPayload = null; // Store the payload that caused the validation error
468
528
 
@@ -498,6 +558,12 @@ async function prepareAndValidateMessage(sourcePayload, options = {}, validatorF
498
558
 
499
559
  // Step 3: Success!
500
560
  log.debug(`Transformation succeeded on attempt ${attempt + 1}`);
561
+
562
+ // Restore original grounding settings if they were changed
563
+ if (options._restoreGrounding) {
564
+ await options._restoreGrounding();
565
+ }
566
+
501
567
  return transformedPayload;
502
568
 
503
569
  } catch (error) {
@@ -506,6 +572,12 @@ async function prepareAndValidateMessage(sourcePayload, options = {}, validatorF
506
572
 
507
573
  if (attempt >= maxRetries) {
508
574
  log.error(`All ${maxRetries + 1} attempts failed.`);
575
+
576
+ // Restore original grounding settings even on failure
577
+ if (options._restoreGrounding) {
578
+ await options._restoreGrounding();
579
+ }
580
+
509
581
  throw new Error(`Transformation failed after ${maxRetries + 1} attempts. Last error: ${error.message}`);
510
582
  }
511
583
 
@@ -607,12 +679,24 @@ async function estimateTokenUsage(nextPayload) {
607
679
  async function resetChat() {
608
680
  if (this.chat) {
609
681
  log.debug("Resetting Gemini chat session...");
610
- this.chat = await this.genAIClient.chats.create({
682
+
683
+ // Prepare chat options with grounding if enabled
684
+ const chatOptions = {
611
685
  model: this.modelName,
612
686
  // @ts-ignore
613
687
  config: this.chatConfig,
614
688
  history: [],
615
- });
689
+ };
690
+
691
+ // Only add tools if grounding is explicitly enabled
692
+ if (this.enableGrounding) {
693
+ chatOptions.config.tools = [{
694
+ googleSearch: this.groundingConfig
695
+ }];
696
+ log.debug(`Search grounding preserved during reset (WARNING: costs $35/1k queries)`);
697
+ }
698
+
699
+ this.chat = await this.genAIClient.chats.create(chatOptions);
616
700
  log.debug("Chat session reset.");
617
701
  } else {
618
702
  log.warn("Cannot reset chat session: chat not yet initialized.");
@@ -631,6 +715,24 @@ function getChatHistory() {
631
715
  return this.chat.getHistory();
632
716
  }
633
717
 
718
+ /**
719
+ * Updates system instructions and reinitializes the chat session
720
+ * @this {ExportedAPI}
721
+ * @param {string} newInstructions - The new system instructions
722
+ * @returns {Promise<void>}
723
+ */
724
+ async function updateSystemInstructions(newInstructions) {
725
+ if (!newInstructions || typeof newInstructions !== 'string') {
726
+ throw new Error('System instructions must be a non-empty string');
727
+ }
728
+
729
+ this.systemInstructions = newInstructions.trim();
730
+ this.chatConfig.systemInstruction = this.systemInstructions;
731
+
732
+ log.debug('Updating system instructions and reinitializing chat...');
733
+ await this.init(true); // Force reinitialize with new instructions
734
+ }
735
+
634
736
 
635
737
  /*
636
738
  ----
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... transforms",
5
- "version": "1.0.8",
5
+ "version": "1.0.10",
6
6
  "main": "index.js",
7
7
  "files": [
8
8
  "index.js",
package/types.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type { GoogleGenAI, ThinkingLevel } from '@google/genai';
1
+ import type { GoogleGenAI, ThinkingLevel, HarmCategory, HarmBlockThreshold } from '@google/genai';
2
2
 
3
- export { ThinkingLevel };
3
+ export { ThinkingLevel, HarmCategory, HarmBlockThreshold };
4
4
 
5
5
  export interface ThinkingConfig {
6
6
  /** Indicates whether to include thoughts in the response. If true, thoughts are returned only if the model supports thought and thoughts are available. */
@@ -12,8 +12,8 @@ export interface ThinkingConfig {
12
12
  }
13
13
 
14
14
  export interface SafetySetting {
15
- category: string; // The harm category
16
- threshold: string; // The blocking threshold
15
+ category: HarmCategory; // The harm category
16
+ threshold: HarmBlockThreshold; // The blocking threshold
17
17
  }
18
18
 
19
19
  export interface ChatConfig {
@@ -51,7 +51,9 @@ export interface AITransformerContext {
51
51
  rawMessage?: (payload: Record<string, unknown> | string) => Promise<Record<string, unknown>>; // Function to send raw messages to the model
52
52
  genAIClient?: GoogleGenAI; // Google GenAI client instance
53
53
  onlyJSON?: boolean; // If true, only JSON responses are allowed
54
-
54
+ enableGrounding?: boolean; // Enable Google Search grounding (default: false, WARNING: costs $35/1k queries)
55
+ groundingConfig?: Record<string, any>; // Additional grounding configuration options
56
+
55
57
  }
56
58
 
57
59
  export interface TransformationExample {
@@ -93,6 +95,8 @@ export interface AITransformerOptions {
93
95
  onlyJSON?: boolean; // If true, only JSON responses are allowed
94
96
  asyncValidator?: AsyncValidatorFunction; // Optional async validator function for response validation
95
97
  logLevel?: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal' | 'none'; // Log level for the logger (defaults to 'info', 'none' disables logging)
98
+ enableGrounding?: boolean; // Enable Google Search grounding (default: false, WARNING: costs $35/1k queries)
99
+ groundingConfig?: Record<string, any>; // Additional grounding configuration options
96
100
  }
97
101
 
98
102
  // Async validator function type
@@ -120,6 +124,8 @@ export declare class AITransformer {
120
124
  genAIClient: any;
121
125
  chat: any;
122
126
  logLevel: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal' | 'none';
127
+ enableGrounding: boolean;
128
+ groundingConfig: Record<string, any>;
123
129
 
124
130
  // Methods
125
131
  init(force?: boolean): Promise<void>;
@@ -133,8 +139,8 @@ export declare class AITransformer {
133
139
  getHistory(): Array<any>;
134
140
  estimateTokenUsage(nextPayload: Record<string, unknown> | string): Promise<{ totalTokens: number; breakdown?: any }>;
135
141
  estimate(nextPayload: Record<string, unknown> | string): Promise<{ totalTokens: number; breakdown?: any }>;
142
+ updateSystemInstructions(newInstructions: string): Promise<void>;
136
143
  }
137
144
 
138
145
  // Default export
139
- declare const _default: typeof AITransformer;
140
- export default _default;
146
+ export default AITransformer;