ak-gemini 1.0.54 → 1.0.57

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 +30 -5
  2. package/index.js +44 -8
  3. package/package.json +11 -9
  4. package/types.d.ts +118 -0
package/index.cjs CHANGED
@@ -56,10 +56,14 @@ var logger_default = logger;
56
56
  // index.js
57
57
  var import_meta = {};
58
58
  import_dotenv.default.config();
59
- var { NODE_ENV = "unknown", GEMINI_API_KEY } = process.env;
59
+ var { NODE_ENV = "unknown", GEMINI_API_KEY, LOG_LEVEL = "" } = process.env;
60
60
  if (NODE_ENV === "dev") logger_default.level = "debug";
61
61
  if (NODE_ENV === "test") logger_default.level = "warn";
62
62
  if (NODE_ENV.startsWith("prod")) logger_default.level = "error";
63
+ if (LOG_LEVEL) {
64
+ logger_default.level = LOG_LEVEL;
65
+ logger_default.debug(`Setting log level to ${LOG_LEVEL}`);
66
+ }
63
67
  var DEFAULT_SAFETY_SETTINGS = [
64
68
  { category: import_genai.HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: import_genai.HarmBlockThreshold.BLOCK_NONE },
65
69
  { category: import_genai.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: import_genai.HarmBlockThreshold.BLOCK_NONE }
@@ -115,7 +119,9 @@ var AITransformer = class {
115
119
  this.reset = resetChat.bind(this);
116
120
  this.getHistory = getChatHistory.bind(this);
117
121
  this.messageAndValidate = prepareAndValidateMessage.bind(this);
122
+ this.transformWithValidation = prepareAndValidateMessage.bind(this);
118
123
  this.estimate = estimateTokenUsage.bind(this);
124
+ this.estimateTokenUsage = estimateTokenUsage.bind(this);
119
125
  }
120
126
  };
121
127
  var index_default = AITransformer;
@@ -134,8 +140,8 @@ function AITransformFactory(options = {}) {
134
140
  }
135
141
  this.examplesFile = options.examplesFile || null;
136
142
  this.exampleData = options.exampleData || null;
137
- this.promptKey = options.promptKey || "PROMPT";
138
- this.answerKey = options.answerKey || "ANSWER";
143
+ this.promptKey = options.promptKey || options.sourceKey || "PROMPT";
144
+ this.answerKey = options.answerKey || options.targetKey || "ANSWER";
139
145
  this.contextKey = options.contextKey || "CONTEXT";
140
146
  this.explanationKey = options.explanationKey || "EXPLANATION";
141
147
  this.systemInstructionsKey = options.systemInstructionsKey || "SYSTEM";
@@ -161,6 +167,12 @@ async function initChat(force = false) {
161
167
  config: this.chatConfig,
162
168
  history: []
163
169
  });
170
+ try {
171
+ await this.genAIClient.models.list();
172
+ logger_default.debug("Gemini API connection successful.");
173
+ } catch (e) {
174
+ throw new Error(`Gemini chat initialization failed: ${e.message}`);
175
+ }
164
176
  logger_default.debug("Gemini chat session initialized.");
165
177
  }
166
178
  async function seedWithExamples(examples) {
@@ -173,6 +185,13 @@ async function seedWithExamples(examples) {
173
185
  } catch (err) {
174
186
  throw new Error(`Could not load examples from file: ${this.examplesFile}. Please check the file path and format.`);
175
187
  }
188
+ } else if (this.exampleData) {
189
+ logger_default.debug(`Using example data provided in options.`);
190
+ if (Array.isArray(this.exampleData)) {
191
+ examples = this.exampleData;
192
+ } else {
193
+ throw new Error(`Invalid example data provided. Expected an array of examples.`);
194
+ }
176
195
  } else {
177
196
  logger_default.debug("No examples provided and no examples file specified. Skipping seeding.");
178
197
  return;
@@ -214,14 +233,16 @@ ${contextText}
214
233
  }
215
234
  }
216
235
  const currentHistory = this?.chat?.getHistory() || [];
236
+ logger_default.debug(`Adding ${historyToAdd.length} examples to chat history (${currentHistory.length} current examples)...`);
217
237
  this.chat = await this.genAIClient.chats.create({
218
238
  model: this.modelName,
219
239
  // @ts-ignore
220
240
  config: this.chatConfig,
221
241
  history: [...currentHistory, ...historyToAdd]
222
242
  });
223
- logger_default.debug("Transformation examples seeded successfully.");
224
- return this.chat.getHistory();
243
+ const newHistory = this.chat.getHistory();
244
+ logger_default.debug(`Created new chat session with ${newHistory.length} examples.`);
245
+ return newHistory;
225
246
  }
226
247
  async function rawMessage(sourcePayload) {
227
248
  if (!this.chat) {
@@ -255,6 +276,10 @@ async function prepareAndValidateMessage(sourcePayload, options = {}, validatorF
255
276
  lastPayload = JSON.stringify(sourcePayload, null, 2);
256
277
  } else if (typeof sourcePayload === "string") {
257
278
  lastPayload = sourcePayload;
279
+ } else if (typeof sourcePayload === "boolean" || typeof sourcePayload === "number") {
280
+ lastPayload = sourcePayload.toString();
281
+ } else if (sourcePayload === null || sourcePayload === void 0) {
282
+ lastPayload = JSON.stringify({});
258
283
  } else {
259
284
  throw new Error("Invalid source payload. Must be a JSON object or string.");
260
285
  }
package/index.js CHANGED
@@ -18,7 +18,7 @@
18
18
  //env
19
19
  import dotenv from 'dotenv';
20
20
  dotenv.config();
21
- const { NODE_ENV = "unknown", GEMINI_API_KEY } = process.env;
21
+ const { NODE_ENV = "unknown", GEMINI_API_KEY, LOG_LEVEL = "" } = process.env;
22
22
 
23
23
 
24
24
 
@@ -33,6 +33,11 @@ if (NODE_ENV === 'dev') log.level = 'debug';
33
33
  if (NODE_ENV === 'test') log.level = 'warn';
34
34
  if (NODE_ENV.startsWith('prod')) log.level = 'error';
35
35
 
36
+ if (LOG_LEVEL) {
37
+ log.level = LOG_LEVEL;
38
+ log.debug(`Setting log level to ${LOG_LEVEL}`);
39
+ }
40
+
36
41
 
37
42
 
38
43
  // defaults
@@ -115,7 +120,9 @@ class AITransformer {
115
120
  this.reset = resetChat.bind(this);
116
121
  this.getHistory = getChatHistory.bind(this);
117
122
  this.messageAndValidate = prepareAndValidateMessage.bind(this);
123
+ this.transformWithValidation = prepareAndValidateMessage.bind(this);
118
124
  this.estimate = estimateTokenUsage.bind(this);
125
+ this.estimateTokenUsage = estimateTokenUsage.bind(this);
119
126
  }
120
127
  }
121
128
 
@@ -150,8 +157,8 @@ function AITransformFactory(options = {}) {
150
157
  this.exampleData = options.exampleData || null; // can be used instead of examplesFile
151
158
 
152
159
  // Use configurable keys with fallbacks
153
- this.promptKey = options.promptKey || 'PROMPT';
154
- this.answerKey = options.answerKey || 'ANSWER';
160
+ this.promptKey = options.promptKey || options.sourceKey || 'PROMPT';
161
+ this.answerKey = options.answerKey || options.targetKey || 'ANSWER';
155
162
  this.contextKey = options.contextKey || 'CONTEXT'; // Optional key for context
156
163
  this.explanationKey = options.explanationKey || 'EXPLANATION'; // Optional key for explanations
157
164
  this.systemInstructionsKey = options.systemInstructionsKey || 'SYSTEM'; // Optional key for system instructions
@@ -196,6 +203,15 @@ async function initChat(force = false) {
196
203
  history: [],
197
204
  });
198
205
 
206
+ try {
207
+ await this.genAIClient.models.list();
208
+ log.debug("Gemini API connection successful.");
209
+ } catch (e) {
210
+ throw new Error(`Gemini chat initialization failed: ${e.message}`);
211
+ }
212
+
213
+
214
+
199
215
  log.debug("Gemini chat session initialized.");
200
216
  }
201
217
 
@@ -218,7 +234,18 @@ async function seedWithExamples(examples) {
218
234
  catch (err) {
219
235
  throw new Error(`Could not load examples from file: ${this.examplesFile}. Please check the file path and format.`);
220
236
  }
221
- } else {
237
+ }
238
+
239
+ else if (this.exampleData) {
240
+ log.debug(`Using example data provided in options.`);
241
+ if (Array.isArray(this.exampleData)) {
242
+ examples = this.exampleData;
243
+ } else {
244
+ throw new Error(`Invalid example data provided. Expected an array of examples.`);
245
+ }
246
+ }
247
+
248
+ else {
222
249
  log.debug("No examples provided and no examples file specified. Skipping seeding.");
223
250
  return;
224
251
  }
@@ -267,8 +294,9 @@ async function seedWithExamples(examples) {
267
294
 
268
295
  }
269
296
 
270
- const currentHistory = this?.chat?.getHistory() || [];
271
297
 
298
+ const currentHistory = this?.chat?.getHistory() || [];
299
+ log.debug(`Adding ${historyToAdd.length} examples to chat history (${currentHistory.length} current examples)...`);
272
300
  this.chat = await this.genAIClient.chats.create({
273
301
  model: this.modelName,
274
302
  // @ts-ignore
@@ -276,9 +304,10 @@ async function seedWithExamples(examples) {
276
304
  history: [...currentHistory, ...historyToAdd],
277
305
  });
278
306
 
279
- log.debug("Transformation examples seeded successfully.");
280
307
 
281
- return this.chat.getHistory(); // Return the updated chat history for reference
308
+ const newHistory = this.chat.getHistory();
309
+ log.debug(`Created new chat session with ${newHistory.length} examples.`);
310
+ return newHistory;
282
311
  }
283
312
 
284
313
  /**
@@ -346,7 +375,14 @@ async function prepareAndValidateMessage(sourcePayload, options = {}, validatorF
346
375
  lastPayload = JSON.stringify(sourcePayload, null, 2);
347
376
  } else if (typeof sourcePayload === 'string') {
348
377
  lastPayload = sourcePayload;
349
- } else {
378
+ }
379
+ else if (typeof sourcePayload === 'boolean' || typeof sourcePayload === 'number') {
380
+ lastPayload = sourcePayload.toString();
381
+ }
382
+ else if (sourcePayload === null || sourcePayload === undefined) {
383
+ lastPayload = JSON.stringify({}); // Convert null/undefined to empty object
384
+ }
385
+ else {
350
386
  throw new Error("Invalid source payload. Must be a JSON object or string.");
351
387
  }
352
388
 
package/package.json CHANGED
@@ -2,19 +2,25 @@
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.54",
5
+ "version": "1.0.57",
6
6
  "main": "index.js",
7
7
  "files": [
8
8
  "index.js",
9
9
  "index.cjs",
10
- "types.ts",
10
+ "types.d.ts",
11
11
  "logger.js"
12
12
  ],
13
13
  "types": "types.d.ts",
14
14
  "exports": {
15
15
  ".": {
16
- "import": "./index.js",
17
- "require": "./index.cjs"
16
+ "import": {
17
+ "types": "./types.d.ts",
18
+ "default": "./index.js"
19
+ },
20
+ "require": {
21
+ "types": "./types.d.ts",
22
+ "default": "./index.cjs"
23
+ }
18
24
  }
19
25
  },
20
26
  "repository": {
@@ -29,13 +35,10 @@
29
35
  "prepublishOnly": "npm run build:cjs",
30
36
  "post": "npm publish --access public",
31
37
  "release": "npm version patch && npm publish --access public",
32
- "local": "./scripts/local.sh",
33
- "fire": "./scripts/fire.sh",
34
- "deploy": "./scripts/deploy.sh",
35
- "perms": "chmod +x ./scripts/*.sh",
36
38
  "update-deps": "npx npm-check-updates -u && npm install",
37
39
  "prune": "rm -rf tmp/*",
38
40
  "test": "node --no-warnings --experimental-vm-modules node_modules/jest/bin/jest.js",
41
+ "test:unit": "npm test -- tests/module.test.js",
39
42
  "build:cjs": "esbuild index.js --bundle --platform=node --format=cjs --outfile=index.cjs --external:@google/genai --external:ak-tools --external:dotenv --external:pino-pretty --external:pino"
40
43
  },
41
44
  "type": "module",
@@ -46,7 +49,6 @@
46
49
  ],
47
50
  "license": "ISC",
48
51
  "dependencies": {
49
- "@google-cloud/functions-framework": "^4.0.0",
50
52
  "@google/genai": "^1.4.0",
51
53
  "ak-tools": "^1.0.64",
52
54
  "dotenv": "^16.5.0",
package/types.d.ts ADDED
@@ -0,0 +1,118 @@
1
+ import type { GoogleGenAI } from '@google/genai';
2
+
3
+ export interface SafetySetting {
4
+ category: string; // The harm category
5
+ threshold: string; // The blocking threshold
6
+ }
7
+
8
+ export interface ChatConfig {
9
+ responseMimeType?: string; // MIME type for responses
10
+ temperature?: number; // Controls randomness (0.0 to 1.0)
11
+ topP?: number; // Controls diversity via nucleus sampling
12
+ topK?: number; // Controls diversity by limiting top-k tokens
13
+ systemInstruction?: string; // System instruction for the model
14
+ safetySettings?: SafetySetting[]; // Safety settings array
15
+ responseSchema?: Object; // Schema for validating model responses
16
+ [key: string]: any; // Additional properties for flexibility
17
+ }
18
+
19
+ export interface AITransformerContext {
20
+ modelName?: string;
21
+ systemInstructions?: string;
22
+ chatConfig?: ChatConfig;
23
+ genAI?: any;
24
+ chat?: any;
25
+ examplesFile?: string | null;
26
+ exampleData?: TransformationExample[] | null;
27
+ promptKey?: string;
28
+ answerKey?: string;
29
+ contextKey?: string;
30
+ explanationKey?: string;
31
+ systemInstructionsKey?: string;
32
+ maxRetries?: number;
33
+ retryDelay?: number;
34
+ init?: () => Promise<void>; // Initialization function
35
+ seed?: () => Promise<void>; // Function to seed the transformer with examples
36
+ message?: (payload: Record<string, unknown>) => Promise<Record<string, unknown>>; // Function to send messages to the model
37
+ rebuild?: () => Promise<Record<string, unknown>; // Function to rebuild the transformer
38
+ rawMessage?: (payload: Record<string, unknown>) => Promise<Record<string, unknown>>; // Function to send raw messages to the model
39
+ genAIClient?: GoogleGenAI; // Google GenAI client instance
40
+ onlyJSON?: boolean; // If true, only JSON responses are allowed
41
+
42
+ }
43
+
44
+ export interface TransformationExample {
45
+ CONTEXT?: Record<string, unknown>; // optional context for the transformation
46
+ PROMPT?: Record<string, unknown>; // what the user provides as input
47
+ ANSWER?: Record<string, unknown>; // what the model should return as output
48
+ }
49
+
50
+ export interface ExampleFileContent {
51
+ examples: TransformationExample[];
52
+ }
53
+
54
+ export interface AITransformerOptions {
55
+ // ? https://ai.google.dev/gemini-api/docs/models
56
+ modelName?: string; // The Gemini model to use
57
+ systemInstructions?: string; // Custom system instructions for the model
58
+ chatConfig?: ChatConfig; // Configuration object for the chat session
59
+ examplesFile?: string; // Path to JSON file containing transformation examples
60
+ exampleData?: TransformationExample[]; // Inline examples to seed the transformer
61
+ sourceKey?: string; // Key name for source data in examples (alias for promptKey)
62
+ targetKey?: string; // Key name for target data in examples (alias for answerKey)
63
+ promptKey?: string; // Key for the prompt in examples
64
+ answerKey?: string; // Key for the answer in examples
65
+ contextKey?: string; // Key name for context data in examples
66
+ explanationKey?: string; // Key name for explanation data in examples
67
+ systemInstructionsKey?: string; // Key for system instructions in examples
68
+ maxRetries?: number; // Maximum retry attempts for auto-retry functionality
69
+ retryDelay?: number; // Initial retry delay in milliseconds
70
+ // ? https://ai.google.dev/gemini-api/docs/structured-output
71
+ responseSchema?: Object; // Schema for validating model responses
72
+ apiKey?: string; // API key for Google GenAI
73
+ onlyJSON?: boolean; // If true, only JSON responses are allowed
74
+ asyncValidator?: AsyncValidatorFunction; // Optional async validator function for response validation
75
+ }
76
+
77
+ // Async validator function type
78
+ export type AsyncValidatorFunction = (payload: Record<string, unknown>) => Promise<unknown>;
79
+
80
+
81
+ export declare class AITransformer {
82
+ // Constructor
83
+ constructor(options?: AITransformerOptions);
84
+
85
+ // Properties
86
+ modelName: string;
87
+ promptKey: string;
88
+ answerKey: string;
89
+ contextKey: string;
90
+ explanationKey: string;
91
+ systemInstructionKey: string;
92
+ maxRetries: number;
93
+ retryDelay: number;
94
+ systemInstructions: string;
95
+ chatConfig: ChatConfig;
96
+ apiKey: string;
97
+ onlyJSON: boolean;
98
+ asyncValidator: AsyncValidatorFunction | null;
99
+ genAIClient: any;
100
+ chat: any;
101
+
102
+ // Methods
103
+ init(force?: boolean): Promise<void>;
104
+ seed(examples?: TransformationExample[]): Promise<any>;
105
+ message(payload: Record<string, unknown>, opts?: object, validatorFn?: AsyncValidatorFunction | null): Promise<Record<string, unknown>>;
106
+ rawMessage(sourcePayload: Record<string, unknown> | string): Promise<Record<string, unknown>>;
107
+ transformWithValidation(sourcePayload: Record<string, unknown>, validatorFn: AsyncValidatorFunction, options?: object): Promise<Record<string, unknown>>;
108
+ messageAndValidate(sourcePayload: Record<string, unknown>, validatorFn: AsyncValidatorFunction, options?: object): Promise<Record<string, unknown>>;
109
+ rebuild(lastPayload: Record<string, unknown>, serverError: string): Promise<Record<string, unknown>>;
110
+ reset(): Promise<void>;
111
+ getHistory(): Array<any>;
112
+ estimateTokenUsage(nextPayload: Record<string, unknown> | string): Promise<{ totalTokens: number; breakdown?: any }>;
113
+ estimate(nextPayload: Record<string, unknown> | string): Promise<{ totalTokens: number; breakdown?: any }>;
114
+ }
115
+
116
+ // Default export
117
+ declare const _default: typeof AITransformer;
118
+ export default _default;