@posthog/ai 8.6.2 → 8.6.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.
@@ -395,7 +395,7 @@ function sanitizeValues(obj) {
395
395
  return jsonSafe;
396
396
  }
397
397
 
398
- var version = "8.6.2";
398
+ var version = "8.6.4";
399
399
 
400
400
  const DEFAULT_MAX_DEPTH = 3;
401
401
  const MAX_STACK_LINES = 20;
@@ -506,125 +506,133 @@ const warnIfPostHogAiGateway = baseURL => {
506
506
  * so callers can re-throw the original error reference safely.
507
507
  */
508
508
  const captureAiGeneration = async (client, options) => {
509
- if (!client.capture) {
510
- return;
511
- }
512
- warnIfPostHogAiGateway(options.baseURL);
513
- const traceId = options.traceId ?? v4();
514
- const eventType = options.eventType ?? AIEvent.Generation;
515
- const privacyMode = options.privacyMode ?? false;
516
- const usage = options.usage ?? {};
509
+ try {
510
+ if (!client.capture) {
511
+ return;
512
+ }
513
+ warnIfPostHogAiGateway(options.baseURL);
514
+ const traceId = options.traceId ?? v4();
515
+ const eventType = options.eventType ?? AIEvent.Generation;
516
+ const privacyMode = options.privacyMode ?? false;
517
+ const usage = options.usage ?? {};
517
518
 
518
- // Check privacy before reading or traversing input/output. Besides avoiding
519
- // needless work, this ensures hostile getters/proxies cannot observe a value
520
- // that the caller explicitly requested us to redact.
521
- const shouldRedact = withPrivacyMode(client, privacyMode, false) === null;
522
- const safeInput = shouldRedact ? null : toJsonSafeValue(options.input);
523
- const safeOutput = shouldRedact ? null : toJsonSafeValue(options.output);
524
- let httpStatus = options.httpStatus;
525
- let errorData = {};
526
- if (options.error) {
527
- if (httpStatus === undefined) {
528
- if (typeof options.error === 'object' && 'status' in options.error && typeof options.error.status === 'number') {
529
- httpStatus = options.error.status;
530
- } else {
531
- httpStatus = 500;
519
+ // Check privacy before reading or traversing input/output. Besides avoiding
520
+ // needless work, this ensures hostile getters/proxies cannot observe a value
521
+ // that the caller explicitly requested us to redact.
522
+ const shouldRedact = withPrivacyMode(client, privacyMode, false) === null;
523
+ const safeInput = shouldRedact ? null : toJsonSafeValue(options.input);
524
+ const safeOutput = shouldRedact ? null : toJsonSafeValue(options.output);
525
+ let httpStatus = options.httpStatus;
526
+ let errorData = {};
527
+ if (options.error) {
528
+ if (httpStatus === undefined) {
529
+ if (typeof options.error === 'object' && 'status' in options.error && typeof options.error.status === 'number') {
530
+ httpStatus = options.error.status;
531
+ } else if (typeof options.error === 'object' && 'statusCode' in options.error && typeof options.error.statusCode === 'number') {
532
+ httpStatus = options.error.statusCode;
533
+ } else {
534
+ httpStatus = 500;
535
+ }
532
536
  }
533
- }
534
- let exceptionId;
535
- if (client.options?.enableExceptionAutocapture) {
536
- exceptionId = uuidv7();
537
- client.captureException(options.error, undefined, {
538
- $ai_trace_id: traceId
539
- }, exceptionId);
540
- if (typeof options.error === 'object') {
541
- options.error.__posthog_previously_captured_error = true;
537
+ let exceptionId;
538
+ if (client.options?.enableExceptionAutocapture) {
539
+ exceptionId = uuidv7();
540
+ client.captureException(options.error, undefined, {
541
+ $ai_trace_id: traceId
542
+ }, exceptionId);
543
+ if (typeof options.error === 'object') {
544
+ ;
545
+ options.error.__posthog_previously_captured_error = true;
546
+ }
542
547
  }
548
+ errorData = {
549
+ $ai_is_error: true,
550
+ $ai_error: stringifyError(options.error),
551
+ $exception_event_id: exceptionId
552
+ };
553
+ }
554
+ httpStatus = httpStatus ?? 200;
555
+ let costOverrideData = {};
556
+ if (options.costOverride) {
557
+ const inputCostUSD = (options.costOverride.inputCost ?? 0) * (usage.inputTokens ?? 0);
558
+ const outputCostUSD = (options.costOverride.outputCost ?? 0) * (usage.outputTokens ?? 0);
559
+ costOverrideData = {
560
+ $ai_input_cost_usd: inputCostUSD,
561
+ $ai_output_cost_usd: outputCostUSD,
562
+ $ai_total_cost_usd: inputCostUSD + outputCostUSD
563
+ };
543
564
  }
544
- errorData = {
545
- $ai_is_error: true,
546
- $ai_error: stringifyError(options.error),
547
- $exception_event_id: exceptionId
565
+ const additionalTokenValues = {
566
+ ...(usage.reasoningTokens ? {
567
+ $ai_reasoning_tokens: usage.reasoningTokens
568
+ } : {}),
569
+ ...(usage.cacheReadInputTokens ? {
570
+ $ai_cache_read_input_tokens: usage.cacheReadInputTokens
571
+ } : {}),
572
+ ...(usage.cacheCreationInputTokens ? {
573
+ $ai_cache_creation_input_tokens: usage.cacheCreationInputTokens
574
+ } : {}),
575
+ ...(usage.webSearchCount ? {
576
+ $ai_web_search_count: usage.webSearchCount
577
+ } : {}),
578
+ ...(usage.rawUsage ? {
579
+ $ai_usage: usage.rawUsage
580
+ } : {})
548
581
  };
549
- }
550
- httpStatus = httpStatus ?? 200;
551
- let costOverrideData = {};
552
- if (options.costOverride) {
553
- const inputCostUSD = (options.costOverride.inputCost ?? 0) * (usage.inputTokens ?? 0);
554
- const outputCostUSD = (options.costOverride.outputCost ?? 0) * (usage.outputTokens ?? 0);
555
- costOverrideData = {
556
- $ai_input_cost_usd: inputCostUSD,
557
- $ai_output_cost_usd: outputCostUSD,
558
- $ai_total_cost_usd: inputCostUSD + outputCostUSD
582
+ const properties = {
583
+ $ai_lib: 'posthog-ai',
584
+ $ai_lib_version: version,
585
+ $ai_provider: options.providerOverride ?? options.provider,
586
+ $ai_model: options.modelOverride ?? options.model,
587
+ $ai_model_parameters: options.modelParameters ?? {},
588
+ $ai_input: safeInput,
589
+ $ai_output_choices: safeOutput,
590
+ $ai_http_status: httpStatus,
591
+ $ai_input_tokens: usage.inputTokens ?? 0,
592
+ ...(usage.outputTokens !== undefined ? {
593
+ $ai_output_tokens: usage.outputTokens
594
+ } : {}),
595
+ ...additionalTokenValues,
596
+ $ai_latency: options.latency ?? 0,
597
+ ...(options.timeToFirstToken !== undefined ? {
598
+ $ai_time_to_first_token: options.timeToFirstToken
599
+ } : {}),
600
+ $ai_trace_id: traceId,
601
+ $ai_base_url: options.baseURL ?? '',
602
+ ...options.properties,
603
+ $ai_tokens_source: getTokensSource(options.properties),
604
+ ...(options.distinctId ? {} : {
605
+ $process_person_profile: false
606
+ }),
607
+ ...(options.stopReason ? {
608
+ $ai_stop_reason: options.stopReason
609
+ } : {}),
610
+ ...(options.tools ? {
611
+ $ai_tools: options.tools
612
+ } : {}),
613
+ ...(options.completionId ? {
614
+ $ai_completion_id: options.completionId
615
+ } : {}),
616
+ ...(options.providerMetadata && Object.keys(options.providerMetadata).length > 0 ? {
617
+ $ai_provider_metadata: options.providerMetadata
618
+ } : {}),
619
+ ...errorData,
620
+ ...costOverrideData
559
621
  };
560
- }
561
- const additionalTokenValues = {
562
- ...(usage.reasoningTokens ? {
563
- $ai_reasoning_tokens: usage.reasoningTokens
564
- } : {}),
565
- ...(usage.cacheReadInputTokens ? {
566
- $ai_cache_read_input_tokens: usage.cacheReadInputTokens
567
- } : {}),
568
- ...(usage.cacheCreationInputTokens ? {
569
- $ai_cache_creation_input_tokens: usage.cacheCreationInputTokens
570
- } : {}),
571
- ...(usage.webSearchCount ? {
572
- $ai_web_search_count: usage.webSearchCount
573
- } : {}),
574
- ...(usage.rawUsage ? {
575
- $ai_usage: usage.rawUsage
576
- } : {})
577
- };
578
- const properties = {
579
- $ai_lib: 'posthog-ai',
580
- $ai_lib_version: version,
581
- $ai_provider: options.providerOverride ?? options.provider,
582
- $ai_model: options.modelOverride ?? options.model,
583
- $ai_model_parameters: options.modelParameters ?? {},
584
- $ai_input: safeInput,
585
- $ai_output_choices: safeOutput,
586
- $ai_http_status: httpStatus,
587
- $ai_input_tokens: usage.inputTokens ?? 0,
588
- ...(usage.outputTokens !== undefined ? {
589
- $ai_output_tokens: usage.outputTokens
590
- } : {}),
591
- ...additionalTokenValues,
592
- $ai_latency: options.latency ?? 0,
593
- ...(options.timeToFirstToken !== undefined ? {
594
- $ai_time_to_first_token: options.timeToFirstToken
595
- } : {}),
596
- $ai_trace_id: traceId,
597
- $ai_base_url: options.baseURL ?? '',
598
- ...options.properties,
599
- $ai_tokens_source: getTokensSource(options.properties),
600
- ...(options.distinctId ? {} : {
601
- $process_person_profile: false
602
- }),
603
- ...(options.stopReason ? {
604
- $ai_stop_reason: options.stopReason
605
- } : {}),
606
- ...(options.tools ? {
607
- $ai_tools: options.tools
608
- } : {}),
609
- ...(options.completionId ? {
610
- $ai_completion_id: options.completionId
611
- } : {}),
612
- ...(options.providerMetadata && Object.keys(options.providerMetadata).length > 0 ? {
613
- $ai_provider_metadata: options.providerMetadata
614
- } : {}),
615
- ...errorData,
616
- ...costOverrideData
617
- };
618
- const event = {
619
- distinctId: options.distinctId ?? traceId,
620
- event: eventType,
621
- properties,
622
- groups: options.groups
623
- };
624
- if (options.captureImmediate) {
625
- await client.captureImmediate(event);
626
- } else {
627
- client.capture(event);
622
+ const event = {
623
+ distinctId: options.distinctId ?? traceId,
624
+ event: eventType,
625
+ properties,
626
+ groups: options.groups
627
+ };
628
+ if (options.captureImmediate) {
629
+ await client.captureImmediate(event);
630
+ } else {
631
+ client.capture(event);
632
+ }
633
+ } catch (error) {
634
+ // Telemetry failures must never affect the instrumented provider call.
635
+ console.warn('[PostHog AI] Failed to capture generation telemetry:', error);
628
636
  }
629
637
  };
630
638