@posthog/ai 7.16.2 → 7.16.3

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/index.mjs CHANGED
@@ -5,7 +5,7 @@ import { uuidv7 } from '@posthog/core';
5
5
  import AnthropicOriginal from '@anthropic-ai/sdk';
6
6
  import { GoogleGenAI } from '@google/genai';
7
7
 
8
- var version = "7.16.2";
8
+ var version = "7.16.3";
9
9
 
10
10
  // Type guards for safer type checking
11
11
  const isString = value => {
@@ -2280,28 +2280,6 @@ const extractWebSearchCount = (providerMetadata, usage) => {
2280
2280
  providerMetadata
2281
2281
  });
2282
2282
  };
2283
- // Extract additional token values from provider metadata
2284
- const extractAdditionalTokenValues = providerMetadata => {
2285
- if (providerMetadata && typeof providerMetadata === 'object' && 'anthropic' in providerMetadata && providerMetadata.anthropic && typeof providerMetadata.anthropic === 'object' && 'cacheCreationInputTokens' in providerMetadata.anthropic) {
2286
- return {
2287
- cacheCreationInputTokens: providerMetadata.anthropic.cacheCreationInputTokens
2288
- };
2289
- }
2290
- return {};
2291
- };
2292
- // For Anthropic providers in V3, inputTokens.total is the sum of all tokens (uncached + cache read + cache write).
2293
- // Our cost calculation expects inputTokens to be only the uncached portion for Anthropic.
2294
- // This helper subtracts cache tokens from inputTokens for Anthropic V3 models.
2295
- const adjustAnthropicV3CacheTokens = (model, provider, usage) => {
2296
- if (isV3Model(model) && provider.toLowerCase().includes('anthropic')) {
2297
- const cacheReadTokens = usage.cacheReadInputTokens || 0;
2298
- const cacheWriteTokens = usage.cacheCreationInputTokens || 0;
2299
- const cacheTokens = cacheReadTokens + cacheWriteTokens;
2300
- if (usage.inputTokens && cacheTokens > 0) {
2301
- usage.inputTokens = Math.max(usage.inputTokens - cacheTokens, 0);
2302
- }
2303
- }
2304
- };
2305
2283
  // Helper to extract numeric token value from V2 (number) or V3 (object with .total) usage formats
2306
2284
  const extractTokenCount = value => {
2307
2285
  if (typeof value === 'number') {
@@ -2336,6 +2314,59 @@ const extractCacheReadTokens = usage => {
2336
2314
  }
2337
2315
  return undefined;
2338
2316
  };
2317
+ // Helper to extract cache write tokens from V3 (usage.inputTokens.cacheWrite). Providers like
2318
+ // Amazon Bedrock populate this standardized field instead of providerMetadata.anthropic.
2319
+ const extractCacheWriteTokens = usage => {
2320
+ if ('inputTokens' in usage && usage.inputTokens && typeof usage.inputTokens === 'object' && 'cacheWrite' in usage.inputTokens) {
2321
+ return usage.inputTokens.cacheWrite;
2322
+ }
2323
+ return undefined;
2324
+ };
2325
+ // Extract additional token values from provider metadata, with a V3 standardized fallback
2326
+ // (e.g. Amazon Bedrock exposes cache write tokens via usage.inputTokens.cacheWrite rather
2327
+ // than providerMetadata.anthropic.cacheCreationInputTokens). A cacheWrite of 0 is treated
2328
+ // as absent so we preserve the pre-fallback event shape on providers that simply omit the
2329
+ // field — consumers downstream saw `$ai_cache_creation_input_tokens` missing, not 0.
2330
+ const extractAdditionalTokenValues = (providerMetadata, usage) => {
2331
+ if (providerMetadata && typeof providerMetadata === 'object' && 'anthropic' in providerMetadata && providerMetadata.anthropic && typeof providerMetadata.anthropic === 'object' && 'cacheCreationInputTokens' in providerMetadata.anthropic) {
2332
+ return {
2333
+ cacheCreationInputTokens: providerMetadata.anthropic.cacheCreationInputTokens
2334
+ };
2335
+ }
2336
+ if (usage && typeof usage === 'object') {
2337
+ const cacheWrite = extractCacheWriteTokens(usage);
2338
+ if (typeof cacheWrite === 'number' && cacheWrite > 0) {
2339
+ return {
2340
+ cacheCreationInputTokens: cacheWrite
2341
+ };
2342
+ }
2343
+ }
2344
+ return {};
2345
+ };
2346
+ // Detects Anthropic Claude regardless of host (direct Anthropic, Amazon Bedrock, Google Vertex, etc.).
2347
+ // The server applies exclusive cache token accounting based on the model name, so any Claude model
2348
+ // needs its V3 input tokens adjusted to exclude cache tokens — not just those routed through a
2349
+ // provider whose name contains "anthropic". Accepts the resolved modelId string (not the raw model)
2350
+ // so it sees the same id the server does after posthogModelOverride / response.modelId fallbacks.
2351
+ const isAnthropicClaudeModel = (modelId, provider) => {
2352
+ if (provider.toLowerCase().includes('anthropic')) {
2353
+ return true;
2354
+ }
2355
+ return /claude|anthropic/i.test(modelId);
2356
+ };
2357
+ // For Anthropic providers in V3, inputTokens.total is the sum of all tokens (uncached + cache read + cache write).
2358
+ // Our cost calculation expects inputTokens to be only the uncached portion for Anthropic.
2359
+ // This helper subtracts cache tokens from inputTokens for Anthropic V3 models.
2360
+ const adjustAnthropicV3CacheTokens = (model, modelId, provider, usage) => {
2361
+ if (isV3Model(model) && isAnthropicClaudeModel(modelId, provider)) {
2362
+ const cacheReadTokens = usage.cacheReadInputTokens || 0;
2363
+ const cacheWriteTokens = usage.cacheCreationInputTokens || 0;
2364
+ const cacheTokens = cacheReadTokens + cacheWriteTokens;
2365
+ if (usage.inputTokens && cacheTokens > 0) {
2366
+ usage.inputTokens = Math.max(usage.inputTokens - cacheTokens, 0);
2367
+ }
2368
+ }
2369
+ };
2339
2370
  /**
2340
2371
  * Wraps a Vercel AI SDK language model (V2 or V3) with PostHog tracing.
2341
2372
  * Automatically detects the model version and applies appropriate instrumentation.
@@ -2372,7 +2403,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
2372
2403
  const content = mapVercelOutput(result.content ?? []);
2373
2404
  const latency = (Date.now() - startTime) / 1000;
2374
2405
  const providerMetadata = result.providerMetadata;
2375
- const additionalTokenValues = extractAdditionalTokenValues(providerMetadata);
2406
+ const additionalTokenValues = extractAdditionalTokenValues(providerMetadata, result.usage);
2376
2407
  const webSearchCount = extractWebSearchCount(providerMetadata, result.usage);
2377
2408
  // V2 usage has simple numbers, V3 has objects with .total - normalize both
2378
2409
  const usageObj = result.usage;
@@ -2400,7 +2431,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
2400
2431
  ...additionalTokenValues,
2401
2432
  rawUsage: rawUsageData
2402
2433
  };
2403
- adjustAnthropicV3CacheTokens(model, provider, usage);
2434
+ adjustAnthropicV3CacheTokens(model, modelId, provider, usage);
2404
2435
  // Extract finish reason - V2 returns a string, V3 returns an object with .unified
2405
2436
  const rawFinishReason = result.finishReason;
2406
2437
  const finishReasonStr = typeof rawFinishReason === 'string' ? rawFinishReason : rawFinishReason && typeof rawFinishReason === 'object' && 'unified' in rawFinishReason ? String(rawFinishReason.unified) : undefined;
@@ -2524,8 +2555,8 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
2524
2555
  }
2525
2556
  if (chunk.type === 'finish') {
2526
2557
  providerMetadata = chunk.providerMetadata;
2527
- const additionalTokenValues = extractAdditionalTokenValues(providerMetadata);
2528
2558
  const chunkUsage = chunk.usage || {};
2559
+ const additionalTokenValues = extractAdditionalTokenValues(providerMetadata, chunkUsage);
2529
2560
  usage = {
2530
2561
  inputTokens: extractTokenCount(chunk.usage?.inputTokens),
2531
2562
  outputTokens: extractTokenCount(chunk.usage?.outputTokens),
@@ -2588,7 +2619,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
2588
2619
  providerMetadata
2589
2620
  }
2590
2621
  };
2591
- adjustAnthropicV3CacheTokens(model, provider, finalUsage);
2622
+ adjustAnthropicV3CacheTokens(model, modelId, provider, finalUsage);
2592
2623
  await sendEventToPosthog({
2593
2624
  client: phClient,
2594
2625
  distinctId: mergedOptions.posthogDistinctId,