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.
- package/index.cjs +30 -5
- package/index.js +44 -8
- package/package.json +11 -9
- 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
|
-
|
|
224
|
-
|
|
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
|
-
}
|
|
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
|
-
|
|
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
|
-
}
|
|
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.
|
|
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":
|
|
17
|
-
|
|
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;
|