@posthog/ai 8.7.0 → 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.
- package/dist/anthropic/index.cjs +61 -17
- package/dist/anthropic/index.cjs.map +1 -1
- package/dist/anthropic/index.mjs +61 -17
- package/dist/anthropic/index.mjs.map +1 -1
- package/dist/gemini/index.cjs +73 -17
- package/dist/gemini/index.cjs.map +1 -1
- package/dist/gemini/index.mjs +73 -17
- package/dist/gemini/index.mjs.map +1 -1
- package/dist/index.cjs +83 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +83 -39
- package/dist/index.mjs.map +1 -1
- package/dist/langchain/index.cjs +27 -13
- package/dist/langchain/index.cjs.map +1 -1
- package/dist/langchain/index.mjs +27 -13
- package/dist/langchain/index.mjs.map +1 -1
- package/dist/openai/index.cjs +91 -47
- package/dist/openai/index.cjs.map +1 -1
- package/dist/openai/index.mjs +91 -47
- package/dist/openai/index.mjs.map +1 -1
- package/dist/openai-agents/index.cjs +25 -4
- package/dist/openai-agents/index.cjs.map +1 -1
- package/dist/openai-agents/index.mjs +25 -4
- package/dist/openai-agents/index.mjs.map +1 -1
- package/dist/otel/index.cjs +1 -5
- package/dist/otel/index.cjs.map +1 -1
- package/dist/otel/index.mjs +1 -5
- package/dist/otel/index.mjs.map +1 -1
- package/dist/vercel/index.cjs +92 -39
- package/dist/vercel/index.cjs.map +1 -1
- package/dist/vercel/index.mjs +92 -39
- package/dist/vercel/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/anthropic/index.mjs
CHANGED
|
@@ -3,6 +3,33 @@ import { v4 } from 'uuid';
|
|
|
3
3
|
import { toJsonSafeValue, uuidv7 } from '@posthog/core';
|
|
4
4
|
import { Stream } from '@anthropic-ai/sdk/streaming';
|
|
5
5
|
|
|
6
|
+
/** @internal */
|
|
7
|
+
|
|
8
|
+
/** @internal */
|
|
9
|
+
|
|
10
|
+
/** @internal */
|
|
11
|
+
function isFullAiCaptureEnabled(client) {
|
|
12
|
+
return client?.enableFullAiCapture === true;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** @internal */
|
|
16
|
+
function captureAiEvent(client, event) {
|
|
17
|
+
if (isFullAiCaptureEnabled(client) && typeof client.captureAi === 'function') {
|
|
18
|
+
client.captureAi(event);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
client.capture(event);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** @internal */
|
|
25
|
+
async function captureAiEventImmediate(client, event) {
|
|
26
|
+
if (isFullAiCaptureEnabled(client) && typeof client.captureAiImmediate === 'function') {
|
|
27
|
+
await client.captureAiImmediate(event);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
await client.captureImmediate(event);
|
|
31
|
+
}
|
|
32
|
+
|
|
6
33
|
const DATA_URL_PREFIX_RE = /^data:([^;,\s]+)(?:;[^;,\s]+)*;base64,/i;
|
|
7
34
|
const BASE64_ALPHABET_RE = /^[A-Za-z0-9+/_=-]+$/;
|
|
8
35
|
class Base64Recognizer {
|
|
@@ -108,7 +135,6 @@ class BinaryContentRedactor {
|
|
|
108
135
|
this.recognizer = recognizer;
|
|
109
136
|
}
|
|
110
137
|
redact(value, mediaType) {
|
|
111
|
-
if (this.isMultimodalEnabled()) return value;
|
|
112
138
|
this.visited = new WeakSet();
|
|
113
139
|
return this.walk(value, mediaType ? new MediaTypeContext(undefined, undefined, mediaType) : MediaTypeContext.EMPTY);
|
|
114
140
|
}
|
|
@@ -152,21 +178,23 @@ class BinaryContentRedactor {
|
|
|
152
178
|
if (mediaType === 'application/octet-stream') return '[base64 file redacted]';
|
|
153
179
|
return `[base64 ${mediaType} redacted]`;
|
|
154
180
|
}
|
|
155
|
-
isMultimodalEnabled() {
|
|
156
|
-
const val = process.env._INTERNAL_LLMA_MULTIMODAL || '';
|
|
157
|
-
return val.toLowerCase() === 'true' || val === '1' || val.toLowerCase() === 'yes';
|
|
158
|
-
}
|
|
159
181
|
}
|
|
160
182
|
|
|
161
183
|
const redactor = new BinaryContentRedactor();
|
|
162
|
-
const
|
|
184
|
+
const sanitize = (data, client) => isFullAiCaptureEnabled(client) ? data : redactor.redact(data);
|
|
185
|
+
const sanitizeAnthropic = (data, client) => sanitize(data, client);
|
|
163
186
|
|
|
164
187
|
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']);
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Whether the caller supplied their own token counts, which override the ones the SDK
|
|
191
|
+
* derived from the provider response.
|
|
192
|
+
*/
|
|
193
|
+
function hasTokenOverrides(posthogProperties) {
|
|
194
|
+
return !!posthogProperties && Object.keys(posthogProperties).some(key => TOKEN_PROPERTY_KEYS.has(key));
|
|
195
|
+
}
|
|
165
196
|
function getTokensSource(posthogProperties) {
|
|
166
|
-
|
|
167
|
-
return 'passthrough';
|
|
168
|
-
}
|
|
169
|
-
return 'sdk';
|
|
197
|
+
return hasTokenOverrides(posthogProperties) ? 'passthrough' : 'sdk';
|
|
170
198
|
}
|
|
171
199
|
const STRING_FORMAT = 'utf8';
|
|
172
200
|
|
|
@@ -302,7 +330,7 @@ function addDefaults(params) {
|
|
|
302
330
|
};
|
|
303
331
|
}
|
|
304
332
|
|
|
305
|
-
var version = "8.
|
|
333
|
+
var version = "8.8.0";
|
|
306
334
|
|
|
307
335
|
const DEFAULT_MAX_DEPTH = 3;
|
|
308
336
|
const MAX_STACK_LINES = 20;
|
|
@@ -469,6 +497,10 @@ const captureAiGeneration = async (client, options) => {
|
|
|
469
497
|
$ai_total_cost_usd: inputCostUSD + outputCostUSD
|
|
470
498
|
};
|
|
471
499
|
}
|
|
500
|
+
|
|
501
|
+
// The caller's own token counts override the SDK-derived ones further down, via the
|
|
502
|
+
// `options.properties` spread.
|
|
503
|
+
const tokensOverridden = hasTokenOverrides(options.properties);
|
|
472
504
|
const additionalTokenValues = {
|
|
473
505
|
...(usage.reasoningTokens ? {
|
|
474
506
|
$ai_reasoning_tokens: usage.reasoningTokens
|
|
@@ -479,6 +511,18 @@ const captureAiGeneration = async (client, options) => {
|
|
|
479
511
|
...(usage.cacheCreationInputTokens ? {
|
|
480
512
|
$ai_cache_creation_input_tokens: usage.cacheCreationInputTokens
|
|
481
513
|
} : {}),
|
|
514
|
+
// Checked against undefined rather than truthiness, because false is the meaningful
|
|
515
|
+
// value here and a truthiness guard would drop it.
|
|
516
|
+
//
|
|
517
|
+
// Dropped entirely when the caller overrides the token counts: the flag describes how
|
|
518
|
+
// the SDK-derived counts relate to each other, so against passthrough counts it can be
|
|
519
|
+
// wrong in the expensive direction. Declaring inclusive over counts that are actually
|
|
520
|
+
// exclusive makes ingestion subtract the cache pool that was never in the input. A
|
|
521
|
+
// caller who knows their own accounting model can still pass
|
|
522
|
+
// `$ai_cache_reporting_exclusive` themselves, and that value wins.
|
|
523
|
+
...(usage.cacheReportingExclusive !== undefined && !tokensOverridden ? {
|
|
524
|
+
$ai_cache_reporting_exclusive: usage.cacheReportingExclusive
|
|
525
|
+
} : {}),
|
|
482
526
|
...(usage.webSearchCount ? {
|
|
483
527
|
$ai_web_search_count: usage.webSearchCount
|
|
484
528
|
} : {}),
|
|
@@ -535,9 +579,9 @@ const captureAiGeneration = async (client, options) => {
|
|
|
535
579
|
groups: options.groups
|
|
536
580
|
};
|
|
537
581
|
if (options.captureImmediate) {
|
|
538
|
-
await client
|
|
582
|
+
await captureAiEventImmediate(client, event);
|
|
539
583
|
} else {
|
|
540
|
-
client
|
|
584
|
+
captureAiEvent(client, event);
|
|
541
585
|
}
|
|
542
586
|
} catch (error) {
|
|
543
587
|
// Telemetry failures must never affect the instrumented provider call.
|
|
@@ -998,7 +1042,7 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
998
1042
|
...posthogParams,
|
|
999
1043
|
model: anthropicParams.model,
|
|
1000
1044
|
provider: 'anthropic',
|
|
1001
|
-
input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams, 'anthropic')),
|
|
1045
|
+
input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams, 'anthropic'), this.phClient),
|
|
1002
1046
|
output: formattedOutput,
|
|
1003
1047
|
latency,
|
|
1004
1048
|
timeToFirstToken,
|
|
@@ -1014,7 +1058,7 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
1014
1058
|
...posthogParams,
|
|
1015
1059
|
model: anthropicParams.model,
|
|
1016
1060
|
provider: 'anthropic',
|
|
1017
|
-
input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams)),
|
|
1061
|
+
input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams), this.phClient),
|
|
1018
1062
|
output: [],
|
|
1019
1063
|
latency: 0,
|
|
1020
1064
|
baseURL: this.baseURL,
|
|
@@ -1050,7 +1094,7 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
1050
1094
|
...posthogParams,
|
|
1051
1095
|
model: anthropicParams.model,
|
|
1052
1096
|
provider: 'anthropic',
|
|
1053
|
-
input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams)),
|
|
1097
|
+
input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams), this.phClient),
|
|
1054
1098
|
output: formatResponseAnthropic(result),
|
|
1055
1099
|
latency,
|
|
1056
1100
|
baseURL: this.baseURL,
|
|
@@ -1074,7 +1118,7 @@ class WrappedMessages extends AnthropicOriginal.Messages {
|
|
|
1074
1118
|
...posthogParams,
|
|
1075
1119
|
model: anthropicParams.model,
|
|
1076
1120
|
provider: 'anthropic',
|
|
1077
|
-
input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams)),
|
|
1121
|
+
input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams), this.phClient),
|
|
1078
1122
|
output: [],
|
|
1079
1123
|
latency: 0,
|
|
1080
1124
|
baseURL: this.baseURL,
|