@posthog/ai 7.16.2 → 7.16.4

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.
@@ -10,7 +10,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
10
 
11
11
  var AnthropicOriginal__default = /*#__PURE__*/_interopDefault(AnthropicOriginal);
12
12
 
13
- var version = "7.16.2";
13
+ var version = "7.16.4";
14
14
 
15
15
  // Type guards for safer type checking
16
16
 
@@ -2,7 +2,7 @@ import AnthropicOriginal from '@anthropic-ai/sdk';
2
2
  import { v4 } from 'uuid';
3
3
  import { uuidv7 } from '@posthog/core';
4
4
 
5
- var version = "7.16.2";
5
+ var version = "7.16.4";
6
6
 
7
7
  // Type guards for safer type checking
8
8
 
@@ -6,7 +6,7 @@ var genai = require('@google/genai');
6
6
  var uuid = require('uuid');
7
7
  var core = require('@posthog/core');
8
8
 
9
- var version = "7.16.2";
9
+ var version = "7.16.4";
10
10
 
11
11
  // Type guards for safer type checking
12
12
 
@@ -2,7 +2,7 @@ import { GoogleGenAI } from '@google/genai';
2
2
  import { v4 } from 'uuid';
3
3
  import { uuidv7 } from '@posthog/core';
4
4
 
5
- var version = "7.16.2";
5
+ var version = "7.16.4";
6
6
 
7
7
  // Type guards for safer type checking
8
8
 
package/dist/index.cjs CHANGED
@@ -29,7 +29,7 @@ function _interopNamespace(e) {
29
29
  var uuid__namespace = /*#__PURE__*/_interopNamespace(uuid);
30
30
  var AnthropicOriginal__default = /*#__PURE__*/_interopDefault(AnthropicOriginal);
31
31
 
32
- var version = "7.16.2";
32
+ var version = "7.16.4";
33
33
 
34
34
  // Type guards for safer type checking
35
35
  const isString = value => {
@@ -2304,28 +2304,6 @@ const extractWebSearchCount = (providerMetadata, usage) => {
2304
2304
  providerMetadata
2305
2305
  });
2306
2306
  };
2307
- // Extract additional token values from provider metadata
2308
- const extractAdditionalTokenValues = providerMetadata => {
2309
- if (providerMetadata && typeof providerMetadata === 'object' && 'anthropic' in providerMetadata && providerMetadata.anthropic && typeof providerMetadata.anthropic === 'object' && 'cacheCreationInputTokens' in providerMetadata.anthropic) {
2310
- return {
2311
- cacheCreationInputTokens: providerMetadata.anthropic.cacheCreationInputTokens
2312
- };
2313
- }
2314
- return {};
2315
- };
2316
- // For Anthropic providers in V3, inputTokens.total is the sum of all tokens (uncached + cache read + cache write).
2317
- // Our cost calculation expects inputTokens to be only the uncached portion for Anthropic.
2318
- // This helper subtracts cache tokens from inputTokens for Anthropic V3 models.
2319
- const adjustAnthropicV3CacheTokens = (model, provider, usage) => {
2320
- if (isV3Model(model) && provider.toLowerCase().includes('anthropic')) {
2321
- const cacheReadTokens = usage.cacheReadInputTokens || 0;
2322
- const cacheWriteTokens = usage.cacheCreationInputTokens || 0;
2323
- const cacheTokens = cacheReadTokens + cacheWriteTokens;
2324
- if (usage.inputTokens && cacheTokens > 0) {
2325
- usage.inputTokens = Math.max(usage.inputTokens - cacheTokens, 0);
2326
- }
2327
- }
2328
- };
2329
2307
  // Helper to extract numeric token value from V2 (number) or V3 (object with .total) usage formats
2330
2308
  const extractTokenCount = value => {
2331
2309
  if (typeof value === 'number') {
@@ -2360,6 +2338,59 @@ const extractCacheReadTokens = usage => {
2360
2338
  }
2361
2339
  return undefined;
2362
2340
  };
2341
+ // Helper to extract cache write tokens from V3 (usage.inputTokens.cacheWrite). Providers like
2342
+ // Amazon Bedrock populate this standardized field instead of providerMetadata.anthropic.
2343
+ const extractCacheWriteTokens = usage => {
2344
+ if ('inputTokens' in usage && usage.inputTokens && typeof usage.inputTokens === 'object' && 'cacheWrite' in usage.inputTokens) {
2345
+ return usage.inputTokens.cacheWrite;
2346
+ }
2347
+ return undefined;
2348
+ };
2349
+ // Extract additional token values from provider metadata, with a V3 standardized fallback
2350
+ // (e.g. Amazon Bedrock exposes cache write tokens via usage.inputTokens.cacheWrite rather
2351
+ // than providerMetadata.anthropic.cacheCreationInputTokens). A cacheWrite of 0 is treated
2352
+ // as absent so we preserve the pre-fallback event shape on providers that simply omit the
2353
+ // field — consumers downstream saw `$ai_cache_creation_input_tokens` missing, not 0.
2354
+ const extractAdditionalTokenValues = (providerMetadata, usage) => {
2355
+ if (providerMetadata && typeof providerMetadata === 'object' && 'anthropic' in providerMetadata && providerMetadata.anthropic && typeof providerMetadata.anthropic === 'object' && 'cacheCreationInputTokens' in providerMetadata.anthropic) {
2356
+ return {
2357
+ cacheCreationInputTokens: providerMetadata.anthropic.cacheCreationInputTokens
2358
+ };
2359
+ }
2360
+ if (usage && typeof usage === 'object') {
2361
+ const cacheWrite = extractCacheWriteTokens(usage);
2362
+ if (typeof cacheWrite === 'number' && cacheWrite > 0) {
2363
+ return {
2364
+ cacheCreationInputTokens: cacheWrite
2365
+ };
2366
+ }
2367
+ }
2368
+ return {};
2369
+ };
2370
+ // Detects Anthropic Claude regardless of host (direct Anthropic, Amazon Bedrock, Google Vertex, etc.).
2371
+ // The server applies exclusive cache token accounting based on the model name, so any Claude model
2372
+ // needs its V3 input tokens adjusted to exclude cache tokens — not just those routed through a
2373
+ // provider whose name contains "anthropic". Accepts the resolved modelId string (not the raw model)
2374
+ // so it sees the same id the server does after posthogModelOverride / response.modelId fallbacks.
2375
+ const isAnthropicClaudeModel = (modelId, provider) => {
2376
+ if (provider.toLowerCase().includes('anthropic')) {
2377
+ return true;
2378
+ }
2379
+ return /claude|anthropic/i.test(modelId);
2380
+ };
2381
+ // For Anthropic providers in V3, inputTokens.total is the sum of all tokens (uncached + cache read + cache write).
2382
+ // Our cost calculation expects inputTokens to be only the uncached portion for Anthropic.
2383
+ // This helper subtracts cache tokens from inputTokens for Anthropic V3 models.
2384
+ const adjustAnthropicV3CacheTokens = (model, modelId, provider, usage) => {
2385
+ if (isV3Model(model) && isAnthropicClaudeModel(modelId, provider)) {
2386
+ const cacheReadTokens = usage.cacheReadInputTokens || 0;
2387
+ const cacheWriteTokens = usage.cacheCreationInputTokens || 0;
2388
+ const cacheTokens = cacheReadTokens + cacheWriteTokens;
2389
+ if (usage.inputTokens && cacheTokens > 0) {
2390
+ usage.inputTokens = Math.max(usage.inputTokens - cacheTokens, 0);
2391
+ }
2392
+ }
2393
+ };
2363
2394
  /**
2364
2395
  * Wraps a Vercel AI SDK language model (V2 or V3) with PostHog tracing.
2365
2396
  * Automatically detects the model version and applies appropriate instrumentation.
@@ -2396,7 +2427,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
2396
2427
  const content = mapVercelOutput(result.content ?? []);
2397
2428
  const latency = (Date.now() - startTime) / 1000;
2398
2429
  const providerMetadata = result.providerMetadata;
2399
- const additionalTokenValues = extractAdditionalTokenValues(providerMetadata);
2430
+ const additionalTokenValues = extractAdditionalTokenValues(providerMetadata, result.usage);
2400
2431
  const webSearchCount = extractWebSearchCount(providerMetadata, result.usage);
2401
2432
  // V2 usage has simple numbers, V3 has objects with .total - normalize both
2402
2433
  const usageObj = result.usage;
@@ -2424,7 +2455,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
2424
2455
  ...additionalTokenValues,
2425
2456
  rawUsage: rawUsageData
2426
2457
  };
2427
- adjustAnthropicV3CacheTokens(model, provider, usage);
2458
+ adjustAnthropicV3CacheTokens(model, modelId, provider, usage);
2428
2459
  // Extract finish reason - V2 returns a string, V3 returns an object with .unified
2429
2460
  const rawFinishReason = result.finishReason;
2430
2461
  const finishReasonStr = typeof rawFinishReason === 'string' ? rawFinishReason : rawFinishReason && typeof rawFinishReason === 'object' && 'unified' in rawFinishReason ? String(rawFinishReason.unified) : undefined;
@@ -2548,8 +2579,8 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
2548
2579
  }
2549
2580
  if (chunk.type === 'finish') {
2550
2581
  providerMetadata = chunk.providerMetadata;
2551
- const additionalTokenValues = extractAdditionalTokenValues(providerMetadata);
2552
2582
  const chunkUsage = chunk.usage || {};
2583
+ const additionalTokenValues = extractAdditionalTokenValues(providerMetadata, chunkUsage);
2553
2584
  usage = {
2554
2585
  inputTokens: extractTokenCount(chunk.usage?.inputTokens),
2555
2586
  outputTokens: extractTokenCount(chunk.usage?.outputTokens),
@@ -2612,7 +2643,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
2612
2643
  providerMetadata
2613
2644
  }
2614
2645
  };
2615
- adjustAnthropicV3CacheTokens(model, provider, finalUsage);
2646
+ adjustAnthropicV3CacheTokens(model, modelId, provider, finalUsage);
2616
2647
  await sendEventToPosthog({
2617
2648
  client: phClient,
2618
2649
  distinctId: mergedOptions.posthogDistinctId,