@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.
@@ -170,11 +170,16 @@ const redactor = new BinaryContentRedactor();
170
170
  const sanitizeAnthropic = data => redactor.redact(data);
171
171
 
172
172
  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']);
173
+
174
+ /**
175
+ * Whether the caller supplied their own token counts, which override the ones the SDK
176
+ * derived from the provider response.
177
+ */
178
+ function hasTokenOverrides(posthogProperties) {
179
+ return !!posthogProperties && Object.keys(posthogProperties).some(key => TOKEN_PROPERTY_KEYS.has(key));
180
+ }
173
181
  function getTokensSource(posthogProperties) {
174
- if (posthogProperties && Object.keys(posthogProperties).some(key => TOKEN_PROPERTY_KEYS.has(key))) {
175
- return 'passthrough';
176
- }
177
- return 'sdk';
182
+ return hasTokenOverrides(posthogProperties) ? 'passthrough' : 'sdk';
178
183
  }
179
184
  const STRING_FORMAT = 'utf8';
180
185
 
@@ -310,7 +315,7 @@ function addDefaults(params) {
310
315
  };
311
316
  }
312
317
 
313
- var version = "8.7.0";
318
+ var version = "8.7.1";
314
319
 
315
320
  const DEFAULT_MAX_DEPTH = 3;
316
321
  const MAX_STACK_LINES = 20;
@@ -477,6 +482,10 @@ const captureAiGeneration = async (client, options) => {
477
482
  $ai_total_cost_usd: inputCostUSD + outputCostUSD
478
483
  };
479
484
  }
485
+
486
+ // The caller's own token counts override the SDK-derived ones further down, via the
487
+ // `options.properties` spread.
488
+ const tokensOverridden = hasTokenOverrides(options.properties);
480
489
  const additionalTokenValues = {
481
490
  ...(usage.reasoningTokens ? {
482
491
  $ai_reasoning_tokens: usage.reasoningTokens
@@ -487,6 +496,18 @@ const captureAiGeneration = async (client, options) => {
487
496
  ...(usage.cacheCreationInputTokens ? {
488
497
  $ai_cache_creation_input_tokens: usage.cacheCreationInputTokens
489
498
  } : {}),
499
+ // Checked against undefined rather than truthiness, because false is the meaningful
500
+ // value here and a truthiness guard would drop it.
501
+ //
502
+ // Dropped entirely when the caller overrides the token counts: the flag describes how
503
+ // the SDK-derived counts relate to each other, so against passthrough counts it can be
504
+ // wrong in the expensive direction. Declaring inclusive over counts that are actually
505
+ // exclusive makes ingestion subtract the cache pool that was never in the input. A
506
+ // caller who knows their own accounting model can still pass
507
+ // `$ai_cache_reporting_exclusive` themselves, and that value wins.
508
+ ...(usage.cacheReportingExclusive !== undefined && !tokensOverridden ? {
509
+ $ai_cache_reporting_exclusive: usage.cacheReportingExclusive
510
+ } : {}),
490
511
  ...(usage.webSearchCount ? {
491
512
  $ai_web_search_count: usage.webSearchCount
492
513
  } : {}),