@posthog/ai 8.7.0 → 8.7.1

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.
@@ -162,11 +162,16 @@ const redactor = new BinaryContentRedactor();
162
162
  const sanitizeAnthropic = data => redactor.redact(data);
163
163
 
164
164
  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']);
165
+
166
+ /**
167
+ * Whether the caller supplied their own token counts, which override the ones the SDK
168
+ * derived from the provider response.
169
+ */
170
+ function hasTokenOverrides(posthogProperties) {
171
+ return !!posthogProperties && Object.keys(posthogProperties).some(key => TOKEN_PROPERTY_KEYS.has(key));
172
+ }
165
173
  function getTokensSource(posthogProperties) {
166
- if (posthogProperties && Object.keys(posthogProperties).some(key => TOKEN_PROPERTY_KEYS.has(key))) {
167
- return 'passthrough';
168
- }
169
- return 'sdk';
174
+ return hasTokenOverrides(posthogProperties) ? 'passthrough' : 'sdk';
170
175
  }
171
176
  const STRING_FORMAT = 'utf8';
172
177
 
@@ -302,7 +307,7 @@ function addDefaults(params) {
302
307
  };
303
308
  }
304
309
 
305
- var version = "8.7.0";
310
+ var version = "8.7.1";
306
311
 
307
312
  const DEFAULT_MAX_DEPTH = 3;
308
313
  const MAX_STACK_LINES = 20;
@@ -469,6 +474,10 @@ const captureAiGeneration = async (client, options) => {
469
474
  $ai_total_cost_usd: inputCostUSD + outputCostUSD
470
475
  };
471
476
  }
477
+
478
+ // The caller's own token counts override the SDK-derived ones further down, via the
479
+ // `options.properties` spread.
480
+ const tokensOverridden = hasTokenOverrides(options.properties);
472
481
  const additionalTokenValues = {
473
482
  ...(usage.reasoningTokens ? {
474
483
  $ai_reasoning_tokens: usage.reasoningTokens
@@ -479,6 +488,18 @@ const captureAiGeneration = async (client, options) => {
479
488
  ...(usage.cacheCreationInputTokens ? {
480
489
  $ai_cache_creation_input_tokens: usage.cacheCreationInputTokens
481
490
  } : {}),
491
+ // Checked against undefined rather than truthiness, because false is the meaningful
492
+ // value here and a truthiness guard would drop it.
493
+ //
494
+ // Dropped entirely when the caller overrides the token counts: the flag describes how
495
+ // the SDK-derived counts relate to each other, so against passthrough counts it can be
496
+ // wrong in the expensive direction. Declaring inclusive over counts that are actually
497
+ // exclusive makes ingestion subtract the cache pool that was never in the input. A
498
+ // caller who knows their own accounting model can still pass
499
+ // `$ai_cache_reporting_exclusive` themselves, and that value wins.
500
+ ...(usage.cacheReportingExclusive !== undefined && !tokensOverridden ? {
501
+ $ai_cache_reporting_exclusive: usage.cacheReportingExclusive
502
+ } : {}),
482
503
  ...(usage.webSearchCount ? {
483
504
  $ai_web_search_count: usage.webSearchCount
484
505
  } : {}),