ak-gemini 1.0.13 → 1.0.14

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/README.md CHANGED
@@ -205,14 +205,15 @@ Clears conversation history while preserving seeded examples. Useful for startin
205
205
 
206
206
  #### `transformer.getLastUsage()`
207
207
 
208
- Returns structured usage data from the last API response for billing verification. Returns `null` if no API call has been made yet.
208
+ Returns structured usage data for billing verification. Token counts are **cumulative across all retry attempts** - if validation failed and a retry was needed, you see the total tokens consumed, not just the final successful call. Returns `null` if no API call has been made yet.
209
209
 
210
210
  ```js
211
211
  const usage = transformer.getLastUsage();
212
212
  // {
213
- // promptTokens: 150, // Input tokens (includes system instructions + history + message)
214
- // responseTokens: 42, // Output tokens
215
- // totalTokens: 192, // Total tokens from API
213
+ // promptTokens: 300, // CUMULATIVE input tokens across all attempts
214
+ // responseTokens: 84, // CUMULATIVE output tokens across all attempts
215
+ // totalTokens: 384, // CUMULATIVE total tokens
216
+ // attempts: 2, // Number of attempts (1 = first try success, 2+ = retries needed)
216
217
  // modelVersion: 'gemini-2.5-flash-001', // Actual model that responded
217
218
  // requestedModel: 'gemini-2.5-flash', // Model you requested
218
219
  // timestamp: 1703... // When response was received
package/index.cjs CHANGED
@@ -122,6 +122,12 @@ var AITransformer = class {
122
122
  this.logLevel = "info";
123
123
  this.lastResponseMetadata = null;
124
124
  this.exampleCount = 0;
125
+ this._cumulativeUsage = {
126
+ promptTokens: 0,
127
+ responseTokens: 0,
128
+ totalTokens: 0,
129
+ attempts: 0
130
+ };
125
131
  AITransformFactory.call(this, options);
126
132
  this.init = initChat.bind(this);
127
133
  this.seed = seedWithExamples.bind(this);
@@ -469,9 +475,21 @@ async function prepareAndValidateMessage(sourcePayload, options = {}, validatorF
469
475
  if (options.labels) {
470
476
  messageOptions.labels = options.labels;
471
477
  }
478
+ this._cumulativeUsage = {
479
+ promptTokens: 0,
480
+ responseTokens: 0,
481
+ totalTokens: 0,
482
+ attempts: 0
483
+ };
472
484
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
473
485
  try {
474
486
  const transformedPayload = attempt === 0 ? await this.rawMessage(lastPayload, messageOptions) : await this.rebuild(lastPayload, lastError.message);
487
+ if (this.lastResponseMetadata) {
488
+ this._cumulativeUsage.promptTokens += this.lastResponseMetadata.promptTokens || 0;
489
+ this._cumulativeUsage.responseTokens += this.lastResponseMetadata.responseTokens || 0;
490
+ this._cumulativeUsage.totalTokens += this.lastResponseMetadata.totalTokens || 0;
491
+ this._cumulativeUsage.attempts = attempt + 1;
492
+ }
475
493
  lastPayload = transformedPayload;
476
494
  if (validatorFn) {
477
495
  await validatorFn(transformedPayload);
@@ -631,6 +649,13 @@ async function clearConversation() {
631
649
  },
632
650
  history: exampleHistory
633
651
  });
652
+ this.lastResponseMetadata = null;
653
+ this._cumulativeUsage = {
654
+ promptTokens: 0,
655
+ responseTokens: 0,
656
+ totalTokens: 0,
657
+ attempts: 0
658
+ };
634
659
  logger_default.debug(`Conversation cleared. Preserved ${exampleHistory.length} example items.`);
635
660
  }
636
661
  function getLastUsage() {
@@ -638,14 +663,15 @@ function getLastUsage() {
638
663
  return null;
639
664
  }
640
665
  const meta = this.lastResponseMetadata;
666
+ const cumulative = this._cumulativeUsage || { promptTokens: 0, responseTokens: 0, totalTokens: 0, attempts: 1 };
667
+ const useCumulative = cumulative.attempts > 0;
641
668
  return {
642
- // Token breakdown for billing
643
- promptTokens: meta.promptTokens,
644
- // Input tokens (includes system instructions + history + message)
645
- responseTokens: meta.responseTokens,
646
- // Output tokens
647
- totalTokens: meta.totalTokens,
648
- // promptTokens + responseTokens
669
+ // Token breakdown for billing - CUMULATIVE across all retry attempts
670
+ promptTokens: useCumulative ? cumulative.promptTokens : meta.promptTokens,
671
+ responseTokens: useCumulative ? cumulative.responseTokens : meta.responseTokens,
672
+ totalTokens: useCumulative ? cumulative.totalTokens : meta.totalTokens,
673
+ // Number of attempts (1 = success on first try, 2+ = retries were needed)
674
+ attempts: useCumulative ? cumulative.attempts : 1,
649
675
  // Model verification for billing cross-check
650
676
  modelVersion: meta.modelVersion,
651
677
  // Actual model that responded (e.g., 'gemini-2.5-flash-001')
@@ -684,6 +710,12 @@ async function statelessMessage(sourcePayload, options = {}, validatorFn = null)
684
710
  totalTokens: result.usageMetadata?.totalTokenCount || 0,
685
711
  timestamp: Date.now()
686
712
  };
713
+ this._cumulativeUsage = {
714
+ promptTokens: this.lastResponseMetadata.promptTokens,
715
+ responseTokens: this.lastResponseMetadata.responseTokens,
716
+ totalTokens: this.lastResponseMetadata.totalTokens,
717
+ attempts: 1
718
+ };
687
719
  if (result.usageMetadata && logger_default.level !== "silent") {
688
720
  logger_default.debug(`Stateless message metadata:`, {
689
721
  modelVersion: result.modelVersion || "not-provided",
package/index.js CHANGED
@@ -114,6 +114,13 @@ class AITransformer {
114
114
  this.logLevel = 'info'; // default log level
115
115
  this.lastResponseMetadata = null; // stores metadata from last API response
116
116
  this.exampleCount = 0; // tracks number of example history items from seed()
117
+ // Cumulative usage tracking across retry attempts
118
+ this._cumulativeUsage = {
119
+ promptTokens: 0,
120
+ responseTokens: 0,
121
+ totalTokens: 0,
122
+ attempts: 0
123
+ };
117
124
  AITransformFactory.call(this, options);
118
125
 
119
126
  //external API
@@ -640,6 +647,14 @@ async function prepareAndValidateMessage(sourcePayload, options = {}, validatorF
640
647
  messageOptions.labels = options.labels;
641
648
  }
642
649
 
650
+ // Reset cumulative usage tracking for this message call
651
+ this._cumulativeUsage = {
652
+ promptTokens: 0,
653
+ responseTokens: 0,
654
+ totalTokens: 0,
655
+ attempts: 0
656
+ };
657
+
643
658
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
644
659
  try {
645
660
  // Step 1: Get the transformed payload
@@ -647,6 +662,14 @@ async function prepareAndValidateMessage(sourcePayload, options = {}, validatorF
647
662
  ? await this.rawMessage(lastPayload, messageOptions) // Use the new raw method with per-message options
648
663
  : await this.rebuild(lastPayload, lastError.message);
649
664
 
665
+ // Accumulate token usage from this attempt
666
+ if (this.lastResponseMetadata) {
667
+ this._cumulativeUsage.promptTokens += this.lastResponseMetadata.promptTokens || 0;
668
+ this._cumulativeUsage.responseTokens += this.lastResponseMetadata.responseTokens || 0;
669
+ this._cumulativeUsage.totalTokens += this.lastResponseMetadata.totalTokens || 0;
670
+ this._cumulativeUsage.attempts = attempt + 1;
671
+ }
672
+
650
673
  lastPayload = transformedPayload; // Always update lastPayload *before* validation
651
674
 
652
675
  // Step 2: Validate if a validator is provided
@@ -915,15 +938,25 @@ async function clearConversation() {
915
938
  history: exampleHistory,
916
939
  });
917
940
 
941
+ // Reset usage tracking for the new conversation
942
+ this.lastResponseMetadata = null;
943
+ this._cumulativeUsage = {
944
+ promptTokens: 0,
945
+ responseTokens: 0,
946
+ totalTokens: 0,
947
+ attempts: 0
948
+ };
949
+
918
950
  log.debug(`Conversation cleared. Preserved ${exampleHistory.length} example items.`);
919
951
  }
920
952
 
921
953
  /**
922
- * Returns structured usage data from the last API response for billing verification.
954
+ * Returns structured usage data from the last message call for billing verification.
955
+ * Includes CUMULATIVE token counts across all retry attempts.
923
956
  * Call this after message() or statelessMessage() to get actual token consumption.
924
957
  *
925
958
  * @this {ExportedAPI}
926
- * @returns {Object|null} Usage data with promptTokens, responseTokens, totalTokens, modelVersion, etc.
959
+ * @returns {Object|null} Usage data with promptTokens, responseTokens, totalTokens, attempts, etc.
927
960
  * Returns null if no API call has been made yet.
928
961
  */
929
962
  function getLastUsage() {
@@ -932,11 +965,19 @@ function getLastUsage() {
932
965
  }
933
966
 
934
967
  const meta = this.lastResponseMetadata;
968
+ const cumulative = this._cumulativeUsage || { promptTokens: 0, responseTokens: 0, totalTokens: 0, attempts: 1 };
969
+
970
+ // Use cumulative tokens if tracking was active (attempts > 0), otherwise fall back to last response
971
+ const useCumulative = cumulative.attempts > 0;
972
+
935
973
  return {
936
- // Token breakdown for billing
937
- promptTokens: meta.promptTokens, // Input tokens (includes system instructions + history + message)
938
- responseTokens: meta.responseTokens, // Output tokens
939
- totalTokens: meta.totalTokens, // promptTokens + responseTokens
974
+ // Token breakdown for billing - CUMULATIVE across all retry attempts
975
+ promptTokens: useCumulative ? cumulative.promptTokens : meta.promptTokens,
976
+ responseTokens: useCumulative ? cumulative.responseTokens : meta.responseTokens,
977
+ totalTokens: useCumulative ? cumulative.totalTokens : meta.totalTokens,
978
+
979
+ // Number of attempts (1 = success on first try, 2+ = retries were needed)
980
+ attempts: useCumulative ? cumulative.attempts : 1,
940
981
 
941
982
  // Model verification for billing cross-check
942
983
  modelVersion: meta.modelVersion, // Actual model that responded (e.g., 'gemini-2.5-flash-001')
@@ -1001,6 +1042,14 @@ async function statelessMessage(sourcePayload, options = {}, validatorFn = null)
1001
1042
  timestamp: Date.now()
1002
1043
  };
1003
1044
 
1045
+ // Set cumulative usage for stateless message (single attempt, no retries)
1046
+ this._cumulativeUsage = {
1047
+ promptTokens: this.lastResponseMetadata.promptTokens,
1048
+ responseTokens: this.lastResponseMetadata.responseTokens,
1049
+ totalTokens: this.lastResponseMetadata.totalTokens,
1050
+ attempts: 1
1051
+ };
1052
+
1004
1053
  if (result.usageMetadata && log.level !== 'silent') {
1005
1054
  log.debug(`Stateless message metadata:`, {
1006
1055
  modelVersion: result.modelVersion || 'not-provided',
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.13",
5
+ "version": "1.0.14",
6
6
  "main": "index.js",
7
7
  "files": [
8
8
  "index.js",
package/types.d.ts CHANGED
@@ -43,9 +43,10 @@ export interface ResponseMetadata {
43
43
 
44
44
  /** Structured usage data returned by getLastUsage() for billing verification */
45
45
  export interface UsageData {
46
- promptTokens: number; // Input tokens (includes system instructions + history + message)
47
- responseTokens: number; // Output tokens
48
- totalTokens: number; // promptTokens + responseTokens
46
+ promptTokens: number; // CUMULATIVE input tokens across all retry attempts
47
+ responseTokens: number; // CUMULATIVE output tokens across all retry attempts
48
+ totalTokens: number; // CUMULATIVE total tokens across all retry attempts
49
+ attempts: number; // Number of attempts (1 = first try success, 2+ = retries needed)
49
50
  modelVersion: string | null; // Actual model that responded (e.g., 'gemini-2.5-flash-001')
50
51
  requestedModel: string; // Model you requested (e.g., 'gemini-2.5-flash')
51
52
  timestamp: number; // When response was received
@@ -91,6 +92,7 @@ export interface AITransformerContext {
91
92
  lastResponseMetadata?: ResponseMetadata | null; // Metadata from the last API response
92
93
  exampleCount?: number; // Number of example history items from seed()
93
94
  clearConversation?: () => Promise<void>; // Clears conversation history while preserving examples
95
+ _cumulativeUsage?: { promptTokens: number; responseTokens: number; totalTokens: number; attempts: number }; // Internal cumulative tracking
94
96
  }
95
97
 
96
98
  export interface TransformationExample {