@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/langchain/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import 'buffer';
|
|
|
2
2
|
import * as uuid from 'uuid';
|
|
3
3
|
import '@posthog/core';
|
|
4
4
|
|
|
5
|
-
var version = "7.
|
|
5
|
+
var version = "7.6.0";
|
|
6
6
|
|
|
7
7
|
// Type guards for safer type checking
|
|
8
8
|
|
|
@@ -13,6 +13,136 @@ const isObject = value => {
|
|
|
13
13
|
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
+
const REDACTED_IMAGE_PLACEHOLDER = '[base64 image redacted]';
|
|
17
|
+
|
|
18
|
+
// ============================================
|
|
19
|
+
// Multimodal Feature Toggle
|
|
20
|
+
// ============================================
|
|
21
|
+
|
|
22
|
+
const isMultimodalEnabled = () => {
|
|
23
|
+
const val = process.env._INTERNAL_LLMA_MULTIMODAL || '';
|
|
24
|
+
return val.toLowerCase() === 'true' || val === '1' || val.toLowerCase() === 'yes';
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// ============================================
|
|
28
|
+
// Base64 Detection Helpers
|
|
29
|
+
// ============================================
|
|
30
|
+
|
|
31
|
+
const isBase64DataUrl = str => {
|
|
32
|
+
return /^data:([^;]+);base64,/.test(str);
|
|
33
|
+
};
|
|
34
|
+
const isValidUrl = str => {
|
|
35
|
+
try {
|
|
36
|
+
new URL(str);
|
|
37
|
+
return true;
|
|
38
|
+
} catch {
|
|
39
|
+
// Not an absolute URL, check if it's a relative URL or path
|
|
40
|
+
return str.startsWith('/') || str.startsWith('./') || str.startsWith('../');
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const isRawBase64 = str => {
|
|
44
|
+
// Skip if it's a valid URL or path
|
|
45
|
+
if (isValidUrl(str)) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Check if it's a valid base64 string
|
|
50
|
+
// Base64 images are typically at least a few hundred chars, but we'll be conservative
|
|
51
|
+
return str.length > 20 && /^[A-Za-z0-9+/]+=*$/.test(str);
|
|
52
|
+
};
|
|
53
|
+
function redactBase64DataUrl(str) {
|
|
54
|
+
if (isMultimodalEnabled()) return str;
|
|
55
|
+
if (!isString(str)) return str;
|
|
56
|
+
|
|
57
|
+
// Check for data URL format
|
|
58
|
+
if (isBase64DataUrl(str)) {
|
|
59
|
+
return REDACTED_IMAGE_PLACEHOLDER;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Check for raw base64 (Vercel sends raw base64 for inline images)
|
|
63
|
+
if (isRawBase64(str)) {
|
|
64
|
+
return REDACTED_IMAGE_PLACEHOLDER;
|
|
65
|
+
}
|
|
66
|
+
return str;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ============================================
|
|
70
|
+
// Common Message Processing
|
|
71
|
+
// ============================================
|
|
72
|
+
|
|
73
|
+
const processMessages = (messages, transformContent) => {
|
|
74
|
+
if (!messages) return messages;
|
|
75
|
+
const processContent = content => {
|
|
76
|
+
if (typeof content === 'string') return content;
|
|
77
|
+
if (!content) return content;
|
|
78
|
+
if (Array.isArray(content)) {
|
|
79
|
+
return content.map(transformContent);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Handle single object content
|
|
83
|
+
return transformContent(content);
|
|
84
|
+
};
|
|
85
|
+
const processMessage = msg => {
|
|
86
|
+
if (!isObject(msg) || !('content' in msg)) return msg;
|
|
87
|
+
return {
|
|
88
|
+
...msg,
|
|
89
|
+
content: processContent(msg.content)
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Handle both arrays and single messages
|
|
94
|
+
if (Array.isArray(messages)) {
|
|
95
|
+
return messages.map(processMessage);
|
|
96
|
+
}
|
|
97
|
+
return processMessage(messages);
|
|
98
|
+
};
|
|
99
|
+
const sanitizeLangChainImage = item => {
|
|
100
|
+
if (!isObject(item)) return item;
|
|
101
|
+
|
|
102
|
+
// OpenAI style
|
|
103
|
+
if (item.type === 'image_url' && 'image_url' in item && isObject(item.image_url) && 'url' in item.image_url) {
|
|
104
|
+
return {
|
|
105
|
+
...item,
|
|
106
|
+
image_url: {
|
|
107
|
+
...item.image_url,
|
|
108
|
+
url: redactBase64DataUrl(item.image_url.url)
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Direct image with data field
|
|
114
|
+
if (item.type === 'image' && 'data' in item) {
|
|
115
|
+
return {
|
|
116
|
+
...item,
|
|
117
|
+
data: redactBase64DataUrl(item.data)
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Anthropic style
|
|
122
|
+
if (item.type === 'image' && 'source' in item && isObject(item.source) && 'data' in item.source) {
|
|
123
|
+
if (isMultimodalEnabled()) return item;
|
|
124
|
+
return {
|
|
125
|
+
...item,
|
|
126
|
+
source: {
|
|
127
|
+
...item.source,
|
|
128
|
+
data: redactBase64DataUrl(item.source.data)
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Google style
|
|
134
|
+
if (item.type === 'media' && 'data' in item) {
|
|
135
|
+
return {
|
|
136
|
+
...item,
|
|
137
|
+
data: redactBase64DataUrl(item.data)
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
return item;
|
|
141
|
+
};
|
|
142
|
+
const sanitizeLangChain = data => {
|
|
143
|
+
return processMessages(data, sanitizeLangChainImage);
|
|
144
|
+
};
|
|
145
|
+
|
|
16
146
|
/**
|
|
17
147
|
* Safely converts content to a string, preserving structure for objects/arrays.
|
|
18
148
|
* - If content is already a string, returns it as-is
|
|
@@ -262,6 +392,20 @@ function isSerializableLike(obj) {
|
|
|
262
392
|
return obj !== null && typeof obj === "object" && "lc_serializable" in obj && typeof obj.toJSON === "function";
|
|
263
393
|
}
|
|
264
394
|
/**
|
|
395
|
+
* Create a "not_implemented" serialization result for objects that cannot be serialized.
|
|
396
|
+
*/
|
|
397
|
+
function createNotImplemented(obj) {
|
|
398
|
+
let id;
|
|
399
|
+
if (obj !== null && typeof obj === "object") if ("lc_id" in obj && Array.isArray(obj.lc_id)) id = obj.lc_id;
|
|
400
|
+
else id = [obj.constructor?.name ?? "Object"];
|
|
401
|
+
else id = [typeof obj];
|
|
402
|
+
return {
|
|
403
|
+
lc: 1,
|
|
404
|
+
type: "not_implemented",
|
|
405
|
+
id
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
265
409
|
* Escape a value if it needs escaping (contains `lc` key).
|
|
266
410
|
*
|
|
267
411
|
* This is a simpler version of `serializeValue` that doesn't handle Serializable
|
|
@@ -269,18 +413,27 @@ function isSerializableLike(obj) {
|
|
|
269
413
|
* processed by `toJSON()`.
|
|
270
414
|
*
|
|
271
415
|
* @param value - The value to potentially escape.
|
|
416
|
+
* @param pathSet - WeakSet to track ancestor objects in the current path to detect circular references.
|
|
417
|
+
* Objects are removed after processing to allow shared references (same object in
|
|
418
|
+
* multiple places) while still detecting true circular references (ancestor in descendant).
|
|
272
419
|
* @returns The value with any `lc`-containing objects wrapped in escape markers.
|
|
273
420
|
*/
|
|
274
|
-
function escapeIfNeeded(value) {
|
|
421
|
+
function escapeIfNeeded(value, pathSet = /* @__PURE__ */ new WeakSet()) {
|
|
275
422
|
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
423
|
+
if (pathSet.has(value)) return createNotImplemented(value);
|
|
276
424
|
if (isSerializableLike(value)) return value;
|
|
425
|
+
pathSet.add(value);
|
|
277
426
|
const record = value;
|
|
278
|
-
if (needsEscaping(record))
|
|
427
|
+
if (needsEscaping(record)) {
|
|
428
|
+
pathSet.delete(value);
|
|
429
|
+
return escapeObject(record);
|
|
430
|
+
}
|
|
279
431
|
const result = {};
|
|
280
|
-
for (const [key, val] of Object.entries(record)) result[key] = escapeIfNeeded(val);
|
|
432
|
+
for (const [key, val] of Object.entries(record)) result[key] = escapeIfNeeded(val, pathSet);
|
|
433
|
+
pathSet.delete(value);
|
|
281
434
|
return result;
|
|
282
435
|
}
|
|
283
|
-
if (Array.isArray(value)) return value.map((item) => escapeIfNeeded(item));
|
|
436
|
+
if (Array.isArray(value)) return value.map((item) => escapeIfNeeded(item, pathSet));
|
|
284
437
|
return value;
|
|
285
438
|
}
|
|
286
439
|
|
|
@@ -406,7 +559,9 @@ var Serializable = class Serializable {
|
|
|
406
559
|
if (last in read && read[last] !== void 0) write[last] = write[last] || read[last];
|
|
407
560
|
});
|
|
408
561
|
const escapedKwargs = {};
|
|
409
|
-
|
|
562
|
+
const pathSet = /* @__PURE__ */ new WeakSet();
|
|
563
|
+
pathSet.add(this);
|
|
564
|
+
for (const [key, value] of Object.entries(kwargs)) escapedKwargs[key] = escapeIfNeeded(value, pathSet);
|
|
410
565
|
const kwargsWithSecrets = Object.keys(secrets).length ? replaceSecrets(escapedKwargs, secrets) : escapedKwargs;
|
|
411
566
|
const processedKwargs = mapKeys(kwargsWithSecrets, keyToJson, aliases);
|
|
412
567
|
return {
|
|
@@ -577,136 +732,6 @@ const isBaseCallbackHandler = (x) => {
|
|
|
577
732
|
return callbackHandler !== void 0 && typeof callbackHandler.copy === "function" && typeof callbackHandler.name === "string" && typeof callbackHandler.awaitHandlers === "boolean";
|
|
578
733
|
};
|
|
579
734
|
|
|
580
|
-
const REDACTED_IMAGE_PLACEHOLDER = '[base64 image redacted]';
|
|
581
|
-
|
|
582
|
-
// ============================================
|
|
583
|
-
// Multimodal Feature Toggle
|
|
584
|
-
// ============================================
|
|
585
|
-
|
|
586
|
-
const isMultimodalEnabled = () => {
|
|
587
|
-
const val = process.env._INTERNAL_LLMA_MULTIMODAL || '';
|
|
588
|
-
return val.toLowerCase() === 'true' || val === '1' || val.toLowerCase() === 'yes';
|
|
589
|
-
};
|
|
590
|
-
|
|
591
|
-
// ============================================
|
|
592
|
-
// Base64 Detection Helpers
|
|
593
|
-
// ============================================
|
|
594
|
-
|
|
595
|
-
const isBase64DataUrl = str => {
|
|
596
|
-
return /^data:([^;]+);base64,/.test(str);
|
|
597
|
-
};
|
|
598
|
-
const isValidUrl = str => {
|
|
599
|
-
try {
|
|
600
|
-
new URL(str);
|
|
601
|
-
return true;
|
|
602
|
-
} catch {
|
|
603
|
-
// Not an absolute URL, check if it's a relative URL or path
|
|
604
|
-
return str.startsWith('/') || str.startsWith('./') || str.startsWith('../');
|
|
605
|
-
}
|
|
606
|
-
};
|
|
607
|
-
const isRawBase64 = str => {
|
|
608
|
-
// Skip if it's a valid URL or path
|
|
609
|
-
if (isValidUrl(str)) {
|
|
610
|
-
return false;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
// Check if it's a valid base64 string
|
|
614
|
-
// Base64 images are typically at least a few hundred chars, but we'll be conservative
|
|
615
|
-
return str.length > 20 && /^[A-Za-z0-9+/]+=*$/.test(str);
|
|
616
|
-
};
|
|
617
|
-
function redactBase64DataUrl(str) {
|
|
618
|
-
if (isMultimodalEnabled()) return str;
|
|
619
|
-
if (!isString(str)) return str;
|
|
620
|
-
|
|
621
|
-
// Check for data URL format
|
|
622
|
-
if (isBase64DataUrl(str)) {
|
|
623
|
-
return REDACTED_IMAGE_PLACEHOLDER;
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
// Check for raw base64 (Vercel sends raw base64 for inline images)
|
|
627
|
-
if (isRawBase64(str)) {
|
|
628
|
-
return REDACTED_IMAGE_PLACEHOLDER;
|
|
629
|
-
}
|
|
630
|
-
return str;
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
// ============================================
|
|
634
|
-
// Common Message Processing
|
|
635
|
-
// ============================================
|
|
636
|
-
|
|
637
|
-
const processMessages = (messages, transformContent) => {
|
|
638
|
-
if (!messages) return messages;
|
|
639
|
-
const processContent = content => {
|
|
640
|
-
if (typeof content === 'string') return content;
|
|
641
|
-
if (!content) return content;
|
|
642
|
-
if (Array.isArray(content)) {
|
|
643
|
-
return content.map(transformContent);
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
// Handle single object content
|
|
647
|
-
return transformContent(content);
|
|
648
|
-
};
|
|
649
|
-
const processMessage = msg => {
|
|
650
|
-
if (!isObject(msg) || !('content' in msg)) return msg;
|
|
651
|
-
return {
|
|
652
|
-
...msg,
|
|
653
|
-
content: processContent(msg.content)
|
|
654
|
-
};
|
|
655
|
-
};
|
|
656
|
-
|
|
657
|
-
// Handle both arrays and single messages
|
|
658
|
-
if (Array.isArray(messages)) {
|
|
659
|
-
return messages.map(processMessage);
|
|
660
|
-
}
|
|
661
|
-
return processMessage(messages);
|
|
662
|
-
};
|
|
663
|
-
const sanitizeLangChainImage = item => {
|
|
664
|
-
if (!isObject(item)) return item;
|
|
665
|
-
|
|
666
|
-
// OpenAI style
|
|
667
|
-
if (item.type === 'image_url' && 'image_url' in item && isObject(item.image_url) && 'url' in item.image_url) {
|
|
668
|
-
return {
|
|
669
|
-
...item,
|
|
670
|
-
image_url: {
|
|
671
|
-
...item.image_url,
|
|
672
|
-
url: redactBase64DataUrl(item.image_url.url)
|
|
673
|
-
}
|
|
674
|
-
};
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
// Direct image with data field
|
|
678
|
-
if (item.type === 'image' && 'data' in item) {
|
|
679
|
-
return {
|
|
680
|
-
...item,
|
|
681
|
-
data: redactBase64DataUrl(item.data)
|
|
682
|
-
};
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
// Anthropic style
|
|
686
|
-
if (item.type === 'image' && 'source' in item && isObject(item.source) && 'data' in item.source) {
|
|
687
|
-
if (isMultimodalEnabled()) return item;
|
|
688
|
-
return {
|
|
689
|
-
...item,
|
|
690
|
-
source: {
|
|
691
|
-
...item.source,
|
|
692
|
-
data: redactBase64DataUrl(item.source.data)
|
|
693
|
-
}
|
|
694
|
-
};
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
// Google style
|
|
698
|
-
if (item.type === 'media' && 'data' in item) {
|
|
699
|
-
return {
|
|
700
|
-
...item,
|
|
701
|
-
data: redactBase64DataUrl(item.data)
|
|
702
|
-
};
|
|
703
|
-
}
|
|
704
|
-
return item;
|
|
705
|
-
};
|
|
706
|
-
const sanitizeLangChain = data => {
|
|
707
|
-
return processMessages(data, sanitizeLangChainImage);
|
|
708
|
-
};
|
|
709
|
-
|
|
710
735
|
/** A run may either be a Span or a Generation */
|
|
711
736
|
|
|
712
737
|
/** Storage for run metadata */
|