@posthog/ai 8.6.8 → 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.
@@ -172,11 +172,16 @@ function redactBase64DataUrl(str, mediaType) {
172
172
  const sanitizeVercel = data => redactor.redact(data);
173
173
 
174
174
  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']);
175
+
176
+ /**
177
+ * Whether the caller supplied their own token counts, which override the ones the SDK
178
+ * derived from the provider response.
179
+ */
180
+ function hasTokenOverrides(posthogProperties) {
181
+ return !!posthogProperties && Object.keys(posthogProperties).some(key => TOKEN_PROPERTY_KEYS.has(key));
182
+ }
175
183
  function getTokensSource(posthogProperties) {
176
- if (posthogProperties && Object.keys(posthogProperties).some(key => TOKEN_PROPERTY_KEYS.has(key))) {
177
- return 'passthrough';
178
- }
179
- return 'sdk';
184
+ return hasTokenOverrides(posthogProperties) ? 'passthrough' : 'sdk';
180
185
  }
181
186
 
182
187
  // limit large outputs by truncating to 200kb (approx 200k bytes)
@@ -406,7 +411,7 @@ function sanitizeValues(obj) {
406
411
  return jsonSafe;
407
412
  }
408
413
 
409
- var version = "8.6.8";
414
+ var version = "8.7.1";
410
415
 
411
416
  const DEFAULT_MAX_DEPTH = 3;
412
417
  const MAX_STACK_LINES = 20;
@@ -573,6 +578,10 @@ const captureAiGeneration = async (client, options) => {
573
578
  $ai_total_cost_usd: inputCostUSD + outputCostUSD
574
579
  };
575
580
  }
581
+
582
+ // The caller's own token counts override the SDK-derived ones further down, via the
583
+ // `options.properties` spread.
584
+ const tokensOverridden = hasTokenOverrides(options.properties);
576
585
  const additionalTokenValues = {
577
586
  ...(usage.reasoningTokens ? {
578
587
  $ai_reasoning_tokens: usage.reasoningTokens
@@ -583,6 +592,18 @@ const captureAiGeneration = async (client, options) => {
583
592
  ...(usage.cacheCreationInputTokens ? {
584
593
  $ai_cache_creation_input_tokens: usage.cacheCreationInputTokens
585
594
  } : {}),
595
+ // Checked against undefined rather than truthiness, because false is the meaningful
596
+ // value here and a truthiness guard would drop it.
597
+ //
598
+ // Dropped entirely when the caller overrides the token counts: the flag describes how
599
+ // the SDK-derived counts relate to each other, so against passthrough counts it can be
600
+ // wrong in the expensive direction. Declaring inclusive over counts that are actually
601
+ // exclusive makes ingestion subtract the cache pool that was never in the input. A
602
+ // caller who knows their own accounting model can still pass
603
+ // `$ai_cache_reporting_exclusive` themselves, and that value wins.
604
+ ...(usage.cacheReportingExclusive !== undefined && !tokensOverridden ? {
605
+ $ai_cache_reporting_exclusive: usage.cacheReportingExclusive
606
+ } : {}),
586
607
  ...(usage.webSearchCount ? {
587
608
  $ai_web_search_count: usage.webSearchCount
588
609
  } : {}),
@@ -655,6 +676,12 @@ const captureAiGeneration = async (client, options) => {
655
676
  function isV3Model(model) {
656
677
  return model.specificationVersion === 'v3';
657
678
  }
679
+ function getSpecificationVersion(model) {
680
+ if (typeof model === 'object' && model !== null && 'specificationVersion' in model) {
681
+ return model.specificationVersion;
682
+ }
683
+ return undefined;
684
+ }
658
685
 
659
686
  // Content types for the output array
660
687
 
@@ -997,6 +1024,10 @@ const adjustAnthropicV3CacheTokens = (model, modelId, provider, usage) => {
997
1024
  * Automatically detects the model version and applies appropriate instrumentation.
998
1025
  */
999
1026
  const wrapVercelLanguageModel = (model, phClient, options) => {
1027
+ const specificationVersion = getSpecificationVersion(model);
1028
+ if (specificationVersion !== 'v2' && specificationVersion !== 'v3') {
1029
+ throw new Error(`[PostHog AI] withTracing supports Vercel AI SDK v5 and v6 models only. ` + `Use @ai-sdk/otel with @posthog/ai/otel for AI SDK v7 models.`);
1030
+ }
1000
1031
  const traceId = options.posthogTraceId ?? v4();
1001
1032
  const mergedOptions = {
1002
1033
  ...options,