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