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