@posthog/ai 7.5.4 → 7.6.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.
- package/dist/anthropic/index.cjs +71 -63
- package/dist/anthropic/index.cjs.map +1 -1
- package/dist/anthropic/index.mjs +71 -63
- package/dist/anthropic/index.mjs.map +1 -1
- package/dist/gemini/index.cjs +106 -54
- package/dist/gemini/index.cjs.map +1 -1
- package/dist/gemini/index.mjs +106 -54
- package/dist/gemini/index.mjs.map +1 -1
- package/dist/index.cjs +308 -223
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +308 -223
- package/dist/index.mjs.map +1 -1
- package/dist/langchain/index.cjs +161 -136
- package/dist/langchain/index.cjs.map +1 -1
- package/dist/langchain/index.mjs +161 -136
- package/dist/langchain/index.mjs.map +1 -1
- package/dist/openai/index.cjs +163 -133
- package/dist/openai/index.cjs.map +1 -1
- package/dist/openai/index.mjs +163 -133
- package/dist/openai/index.mjs.map +1 -1
- package/dist/vercel/index.cjs +82 -57
- package/dist/vercel/index.cjs.map +1 -1
- package/dist/vercel/index.mjs +82 -57
- package/dist/vercel/index.mjs.map +1 -1
- package/package.json +6 -6
package/dist/vercel/index.cjs
CHANGED
|
@@ -4,7 +4,7 @@ var uuid = require('uuid');
|
|
|
4
4
|
var buffer = require('buffer');
|
|
5
5
|
var core = require('@posthog/core');
|
|
6
6
|
|
|
7
|
-
var version = "7.
|
|
7
|
+
var version = "7.6.0";
|
|
8
8
|
|
|
9
9
|
// Type guards for safer type checking
|
|
10
10
|
|
|
@@ -12,6 +12,59 @@ const isString = value => {
|
|
|
12
12
|
return typeof value === 'string';
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
const REDACTED_IMAGE_PLACEHOLDER = '[base64 image redacted]';
|
|
16
|
+
|
|
17
|
+
// ============================================
|
|
18
|
+
// Multimodal Feature Toggle
|
|
19
|
+
// ============================================
|
|
20
|
+
|
|
21
|
+
const isMultimodalEnabled = () => {
|
|
22
|
+
const val = process.env._INTERNAL_LLMA_MULTIMODAL || '';
|
|
23
|
+
return val.toLowerCase() === 'true' || val === '1' || val.toLowerCase() === 'yes';
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// ============================================
|
|
27
|
+
// Base64 Detection Helpers
|
|
28
|
+
// ============================================
|
|
29
|
+
|
|
30
|
+
const isBase64DataUrl = str => {
|
|
31
|
+
return /^data:([^;]+);base64,/.test(str);
|
|
32
|
+
};
|
|
33
|
+
const isValidUrl = str => {
|
|
34
|
+
try {
|
|
35
|
+
new URL(str);
|
|
36
|
+
return true;
|
|
37
|
+
} catch {
|
|
38
|
+
// Not an absolute URL, check if it's a relative URL or path
|
|
39
|
+
return str.startsWith('/') || str.startsWith('./') || str.startsWith('../');
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const isRawBase64 = str => {
|
|
43
|
+
// Skip if it's a valid URL or path
|
|
44
|
+
if (isValidUrl(str)) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Check if it's a valid base64 string
|
|
49
|
+
// Base64 images are typically at least a few hundred chars, but we'll be conservative
|
|
50
|
+
return str.length > 20 && /^[A-Za-z0-9+/]+=*$/.test(str);
|
|
51
|
+
};
|
|
52
|
+
function redactBase64DataUrl(str) {
|
|
53
|
+
if (isMultimodalEnabled()) return str;
|
|
54
|
+
if (!isString(str)) return str;
|
|
55
|
+
|
|
56
|
+
// Check for data URL format
|
|
57
|
+
if (isBase64DataUrl(str)) {
|
|
58
|
+
return REDACTED_IMAGE_PLACEHOLDER;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Check for raw base64 (Vercel sends raw base64 for inline images)
|
|
62
|
+
if (isRawBase64(str)) {
|
|
63
|
+
return REDACTED_IMAGE_PLACEHOLDER;
|
|
64
|
+
}
|
|
65
|
+
return str;
|
|
66
|
+
}
|
|
67
|
+
|
|
15
68
|
// limit large outputs by truncating to 200kb (approx 200k bytes)
|
|
16
69
|
const MAX_OUTPUT_SIZE = 200000;
|
|
17
70
|
const STRING_FORMAT = 'utf8';
|
|
@@ -316,6 +369,9 @@ const sendEventToPosthog = async ({
|
|
|
316
369
|
} : {}),
|
|
317
370
|
...(usage.webSearchCount ? {
|
|
318
371
|
$ai_web_search_count: usage.webSearchCount
|
|
372
|
+
} : {}),
|
|
373
|
+
...(usage.rawUsage ? {
|
|
374
|
+
$ai_usage: usage.rawUsage
|
|
319
375
|
} : {})
|
|
320
376
|
};
|
|
321
377
|
const properties = {
|
|
@@ -360,59 +416,6 @@ const sendEventToPosthog = async ({
|
|
|
360
416
|
return Promise.resolve();
|
|
361
417
|
};
|
|
362
418
|
|
|
363
|
-
const REDACTED_IMAGE_PLACEHOLDER = '[base64 image redacted]';
|
|
364
|
-
|
|
365
|
-
// ============================================
|
|
366
|
-
// Multimodal Feature Toggle
|
|
367
|
-
// ============================================
|
|
368
|
-
|
|
369
|
-
const isMultimodalEnabled = () => {
|
|
370
|
-
const val = process.env._INTERNAL_LLMA_MULTIMODAL || '';
|
|
371
|
-
return val.toLowerCase() === 'true' || val === '1' || val.toLowerCase() === 'yes';
|
|
372
|
-
};
|
|
373
|
-
|
|
374
|
-
// ============================================
|
|
375
|
-
// Base64 Detection Helpers
|
|
376
|
-
// ============================================
|
|
377
|
-
|
|
378
|
-
const isBase64DataUrl = str => {
|
|
379
|
-
return /^data:([^;]+);base64,/.test(str);
|
|
380
|
-
};
|
|
381
|
-
const isValidUrl = str => {
|
|
382
|
-
try {
|
|
383
|
-
new URL(str);
|
|
384
|
-
return true;
|
|
385
|
-
} catch {
|
|
386
|
-
// Not an absolute URL, check if it's a relative URL or path
|
|
387
|
-
return str.startsWith('/') || str.startsWith('./') || str.startsWith('../');
|
|
388
|
-
}
|
|
389
|
-
};
|
|
390
|
-
const isRawBase64 = str => {
|
|
391
|
-
// Skip if it's a valid URL or path
|
|
392
|
-
if (isValidUrl(str)) {
|
|
393
|
-
return false;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// Check if it's a valid base64 string
|
|
397
|
-
// Base64 images are typically at least a few hundred chars, but we'll be conservative
|
|
398
|
-
return str.length > 20 && /^[A-Za-z0-9+/]+=*$/.test(str);
|
|
399
|
-
};
|
|
400
|
-
function redactBase64DataUrl(str) {
|
|
401
|
-
if (isMultimodalEnabled()) return str;
|
|
402
|
-
if (!isString(str)) return str;
|
|
403
|
-
|
|
404
|
-
// Check for data URL format
|
|
405
|
-
if (isBase64DataUrl(str)) {
|
|
406
|
-
return REDACTED_IMAGE_PLACEHOLDER;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
// Check for raw base64 (Vercel sends raw base64 for inline images)
|
|
410
|
-
if (isRawBase64(str)) {
|
|
411
|
-
return REDACTED_IMAGE_PLACEHOLDER;
|
|
412
|
-
}
|
|
413
|
-
return str;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
419
|
// Union types for dual version support
|
|
417
420
|
|
|
418
421
|
// Type guards
|
|
@@ -740,13 +743,31 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
740
743
|
|
|
741
744
|
// V2 usage has simple numbers, V3 has objects with .total - normalize both
|
|
742
745
|
const usageObj = result.usage;
|
|
746
|
+
|
|
747
|
+
// Extract raw response for providers that include detailed usage metadata
|
|
748
|
+
// For Gemini, candidatesTokensDetails is in result.response.body.usageMetadata
|
|
749
|
+
const rawUsageData = {
|
|
750
|
+
usage: result.usage,
|
|
751
|
+
providerMetadata
|
|
752
|
+
};
|
|
753
|
+
|
|
754
|
+
// Include response body usageMetadata if it contains detailed token breakdown (e.g., candidatesTokensDetails)
|
|
755
|
+
if (result.response && typeof result.response === 'object') {
|
|
756
|
+
const responseBody = result.response.body;
|
|
757
|
+
if (responseBody && typeof responseBody === 'object' && 'usageMetadata' in responseBody) {
|
|
758
|
+
rawUsageData.rawResponse = {
|
|
759
|
+
usageMetadata: responseBody.usageMetadata
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
}
|
|
743
763
|
const usage = {
|
|
744
764
|
inputTokens: extractTokenCount(result.usage.inputTokens),
|
|
745
765
|
outputTokens: extractTokenCount(result.usage.outputTokens),
|
|
746
766
|
reasoningTokens: extractReasoningTokens(usageObj),
|
|
747
767
|
cacheReadInputTokens: extractCacheReadTokens(usageObj),
|
|
748
768
|
webSearchCount,
|
|
749
|
-
...additionalTokenValues
|
|
769
|
+
...additionalTokenValues,
|
|
770
|
+
rawUsage: rawUsageData
|
|
750
771
|
};
|
|
751
772
|
adjustAnthropicV3CacheTokens(model, provider, usage);
|
|
752
773
|
await sendEventToPosthog({
|
|
@@ -906,10 +927,14 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
906
927
|
}] : [];
|
|
907
928
|
const webSearchCount = extractWebSearchCount(providerMetadata, usage);
|
|
908
929
|
|
|
909
|
-
// Update usage with web search count
|
|
930
|
+
// Update usage with web search count and raw metadata
|
|
910
931
|
const finalUsage = {
|
|
911
932
|
...usage,
|
|
912
|
-
webSearchCount
|
|
933
|
+
webSearchCount,
|
|
934
|
+
rawUsage: {
|
|
935
|
+
usage,
|
|
936
|
+
providerMetadata
|
|
937
|
+
}
|
|
913
938
|
};
|
|
914
939
|
adjustAnthropicV3CacheTokens(model, provider, finalUsage);
|
|
915
940
|
await sendEventToPosthog({
|