@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.
@@ -12,6 +12,33 @@ const isString = value => {
12
12
  return typeof value === 'string';
13
13
  };
14
14
 
15
+ /** @internal */
16
+
17
+ /** @internal */
18
+
19
+ /** @internal */
20
+ function isFullAiCaptureEnabled(client) {
21
+ return client?.enableFullAiCapture === true;
22
+ }
23
+
24
+ /** @internal */
25
+ function captureAiEvent(client, event) {
26
+ if (isFullAiCaptureEnabled(client) && typeof client.captureAi === 'function') {
27
+ client.captureAi(event);
28
+ return;
29
+ }
30
+ client.capture(event);
31
+ }
32
+
33
+ /** @internal */
34
+ async function captureAiEventImmediate(client, event) {
35
+ if (isFullAiCaptureEnabled(client) && typeof client.captureAiImmediate === 'function') {
36
+ await client.captureAiImmediate(event);
37
+ return;
38
+ }
39
+ await client.captureImmediate(event);
40
+ }
41
+
15
42
  const DATA_URL_PREFIX_RE = /^data:([^;,\s]+)(?:;[^;,\s]+)*;base64,/i;
16
43
  const BASE64_ALPHABET_RE = /^[A-Za-z0-9+/_=-]+$/;
17
44
  class Base64Recognizer {
@@ -117,7 +144,6 @@ class BinaryContentRedactor {
117
144
  this.recognizer = recognizer;
118
145
  }
119
146
  redact(value, mediaType) {
120
- if (this.isMultimodalEnabled()) return value;
121
147
  this.visited = new WeakSet();
122
148
  return this.walk(value, mediaType ? new MediaTypeContext(undefined, undefined, mediaType) : MediaTypeContext.EMPTY);
123
149
  }
@@ -161,17 +187,14 @@ class BinaryContentRedactor {
161
187
  if (mediaType === 'application/octet-stream') return '[base64 file redacted]';
162
188
  return `[base64 ${mediaType} redacted]`;
163
189
  }
164
- isMultimodalEnabled() {
165
- const val = process.env._INTERNAL_LLMA_MULTIMODAL || '';
166
- return val.toLowerCase() === 'true' || val === '1' || val.toLowerCase() === 'yes';
167
- }
168
190
  }
169
191
 
170
192
  const redactor = new BinaryContentRedactor();
171
193
  function redactBase64DataUrl(str, mediaType) {
172
194
  return redactor.redact(str, mediaType);
173
195
  }
174
- const sanitizeGemini = data => redactor.redact(data);
196
+ const sanitize = (data, client) => isFullAiCaptureEnabled(client) ? data : redactor.redact(data);
197
+ const sanitizeGemini = (data, client) => sanitize(data, client);
175
198
 
176
199
  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']);
177
200
 
@@ -257,7 +280,7 @@ const buildInlineDataBlock = (mimeType, data) => {
257
280
  }
258
281
  };
259
282
  };
260
- const formatResponseGemini = response => {
283
+ const formatResponseGemini = (response, client) => {
261
284
  const output = [];
262
285
  if (response.candidates && Array.isArray(response.candidates)) {
263
286
  for (const candidate of response.candidates) {
@@ -296,7 +319,7 @@ const formatResponseGemini = response => {
296
319
  }
297
320
 
298
321
  // Sanitize base64 data for images and other large inline data
299
- data = redactBase64DataUrl(data, mimeType);
322
+ data = isFullAiCaptureEnabled(client) ? data : redactBase64DataUrl(data, mimeType);
300
323
  content.push(buildInlineDataBlock(mimeType, data));
301
324
  }
302
325
  }
@@ -399,7 +422,7 @@ function addDefaults(params) {
399
422
  };
400
423
  }
401
424
 
402
- var version = "8.7.1";
425
+ var version = "8.8.0";
403
426
 
404
427
  const DEFAULT_MAX_DEPTH = 3;
405
428
  const MAX_STACK_LINES = 20;
@@ -648,9 +671,9 @@ const captureAiGeneration = async (client, options) => {
648
671
  groups: options.groups
649
672
  };
650
673
  if (options.captureImmediate) {
651
- await client.captureImmediate(event);
674
+ await captureAiEventImmediate(client, event);
652
675
  } else {
653
- client.capture(event);
676
+ captureAiEvent(client, event);
654
677
  }
655
678
  } catch (error) {
656
679
  // Telemetry failures must never affect the instrumented provider call.
@@ -691,7 +714,7 @@ class WrappedModels {
691
714
  model: geminiParams.model,
692
715
  provider: 'gemini',
693
716
  input: this.formatInputForPostHog(geminiParams),
694
- output: formatResponseGemini(response),
717
+ output: formatResponseGemini(response, this.phClient),
695
718
  latency,
696
719
  baseURL: 'https://generativelanguage.googleapis.com',
697
720
  modelParameters: getModelParams(params),
@@ -1058,7 +1081,7 @@ class WrappedModels {
1058
1081
  return null;
1059
1082
  }
1060
1083
  formatInputForPostHog(params) {
1061
- const sanitized = sanitizeGemini(params.contents);
1084
+ const sanitized = sanitizeGemini(params.contents, this.phClient);
1062
1085
  const messages = this.formatInput(sanitized);
1063
1086
  const systemInstruction = this.extractSystemInstruction(params);
1064
1087
  if (systemInstruction) {