@posthog/ai 8.7.1 → 8.8.0

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.
@@ -8,6 +8,33 @@ const isString = value => {
8
8
  return typeof value === 'string';
9
9
  };
10
10
 
11
+ /** @internal */
12
+
13
+ /** @internal */
14
+
15
+ /** @internal */
16
+ function isFullAiCaptureEnabled(client) {
17
+ return client?.enableFullAiCapture === true;
18
+ }
19
+
20
+ /** @internal */
21
+ function captureAiEvent(client, event) {
22
+ if (isFullAiCaptureEnabled(client) && typeof client.captureAi === 'function') {
23
+ client.captureAi(event);
24
+ return;
25
+ }
26
+ client.capture(event);
27
+ }
28
+
29
+ /** @internal */
30
+ async function captureAiEventImmediate(client, event) {
31
+ if (isFullAiCaptureEnabled(client) && typeof client.captureAiImmediate === 'function') {
32
+ await client.captureAiImmediate(event);
33
+ return;
34
+ }
35
+ await client.captureImmediate(event);
36
+ }
37
+
11
38
  const DATA_URL_PREFIX_RE = /^data:([^;,\s]+)(?:;[^;,\s]+)*;base64,/i;
12
39
  const BASE64_ALPHABET_RE = /^[A-Za-z0-9+/_=-]+$/;
13
40
  class Base64Recognizer {
@@ -113,7 +140,6 @@ class BinaryContentRedactor {
113
140
  this.recognizer = recognizer;
114
141
  }
115
142
  redact(value, mediaType) {
116
- if (this.isMultimodalEnabled()) return value;
117
143
  this.visited = new WeakSet();
118
144
  return this.walk(value, mediaType ? new MediaTypeContext(undefined, undefined, mediaType) : MediaTypeContext.EMPTY);
119
145
  }
@@ -157,17 +183,14 @@ class BinaryContentRedactor {
157
183
  if (mediaType === 'application/octet-stream') return '[base64 file redacted]';
158
184
  return `[base64 ${mediaType} redacted]`;
159
185
  }
160
- isMultimodalEnabled() {
161
- const val = process.env._INTERNAL_LLMA_MULTIMODAL || '';
162
- return val.toLowerCase() === 'true' || val === '1' || val.toLowerCase() === 'yes';
163
- }
164
186
  }
165
187
 
166
188
  const redactor = new BinaryContentRedactor();
167
189
  function redactBase64DataUrl(str, mediaType) {
168
190
  return redactor.redact(str, mediaType);
169
191
  }
170
- const sanitizeGemini = data => redactor.redact(data);
192
+ const sanitize = (data, client) => isFullAiCaptureEnabled(client) ? data : redactor.redact(data);
193
+ const sanitizeGemini = (data, client) => sanitize(data, client);
171
194
 
172
195
  const TOKEN_PROPERTY_KEYS = new Set(['$ai_input_tokens', '$ai_output_tokens', '$ai_cache_read_input_tokens', '$ai_cache_creation_input_tokens', '$ai_total_tokens', '$ai_reasoning_tokens']);
173
196
 
@@ -253,7 +276,7 @@ const buildInlineDataBlock = (mimeType, data) => {
253
276
  }
254
277
  };
255
278
  };
256
- const formatResponseGemini = response => {
279
+ const formatResponseGemini = (response, client) => {
257
280
  const output = [];
258
281
  if (response.candidates && Array.isArray(response.candidates)) {
259
282
  for (const candidate of response.candidates) {
@@ -292,7 +315,7 @@ const formatResponseGemini = response => {
292
315
  }
293
316
 
294
317
  // Sanitize base64 data for images and other large inline data
295
- data = redactBase64DataUrl(data, mimeType);
318
+ data = isFullAiCaptureEnabled(client) ? data : redactBase64DataUrl(data, mimeType);
296
319
  content.push(buildInlineDataBlock(mimeType, data));
297
320
  }
298
321
  }
@@ -395,7 +418,7 @@ function addDefaults(params) {
395
418
  };
396
419
  }
397
420
 
398
- var version = "8.7.1";
421
+ var version = "8.8.0";
399
422
 
400
423
  const DEFAULT_MAX_DEPTH = 3;
401
424
  const MAX_STACK_LINES = 20;
@@ -644,9 +667,9 @@ const captureAiGeneration = async (client, options) => {
644
667
  groups: options.groups
645
668
  };
646
669
  if (options.captureImmediate) {
647
- await client.captureImmediate(event);
670
+ await captureAiEventImmediate(client, event);
648
671
  } else {
649
- client.capture(event);
672
+ captureAiEvent(client, event);
650
673
  }
651
674
  } catch (error) {
652
675
  // Telemetry failures must never affect the instrumented provider call.
@@ -687,7 +710,7 @@ class WrappedModels {
687
710
  model: geminiParams.model,
688
711
  provider: 'gemini',
689
712
  input: this.formatInputForPostHog(geminiParams),
690
- output: formatResponseGemini(response),
713
+ output: formatResponseGemini(response, this.phClient),
691
714
  latency,
692
715
  baseURL: 'https://generativelanguage.googleapis.com',
693
716
  modelParameters: getModelParams(params),
@@ -1054,7 +1077,7 @@ class WrappedModels {
1054
1077
  return null;
1055
1078
  }
1056
1079
  formatInputForPostHog(params) {
1057
- const sanitized = sanitizeGemini(params.contents);
1080
+ const sanitized = sanitizeGemini(params.contents, this.phClient);
1058
1081
  const messages = this.formatInput(sanitized);
1059
1082
  const systemInstruction = this.extractSystemInstruction(params);
1060
1083
  if (systemInstruction) {