@posthog/ai 8.9.0 → 8.9.2

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.
@@ -422,7 +422,7 @@ function addDefaults(params) {
422
422
  };
423
423
  }
424
424
 
425
- var version = "8.9.0";
425
+ var version = "8.9.2";
426
426
 
427
427
  const DEFAULT_MAX_DEPTH = 3;
428
428
  const MAX_STACK_LINES = 20;
@@ -579,15 +579,22 @@ const captureAiGeneration = async (client, options) => {
579
579
  };
580
580
  }
581
581
  httpStatus = httpStatus ?? 200;
582
- let costOverrideData = {};
582
+
583
+ // A configured price applies only to a count the provider reported, so a call with no
584
+ // reported usage sends no cost instead of asserting $0. $ai_total_cost_usd sums the sides
585
+ // that were priced, which makes it the cost of the known side alone when the other side
586
+ // went unreported: a lower bound on the true total, not an assertion of it.
587
+ const costOverrideData = {};
583
588
  if (options.costOverride) {
584
- const inputCostUSD = (options.costOverride.inputCost ?? 0) * (usage.inputTokens ?? 0);
585
- const outputCostUSD = (options.costOverride.outputCost ?? 0) * (usage.outputTokens ?? 0);
586
- costOverrideData = {
587
- $ai_input_cost_usd: inputCostUSD,
588
- $ai_output_cost_usd: outputCostUSD,
589
- $ai_total_cost_usd: inputCostUSD + outputCostUSD
590
- };
589
+ if (usage.inputTokens !== undefined) {
590
+ costOverrideData.$ai_input_cost_usd = (options.costOverride.inputCost ?? 0) * usage.inputTokens;
591
+ }
592
+ if (usage.outputTokens !== undefined) {
593
+ costOverrideData.$ai_output_cost_usd = (options.costOverride.outputCost ?? 0) * usage.outputTokens;
594
+ }
595
+ if (Object.keys(costOverrideData).length > 0) {
596
+ costOverrideData.$ai_total_cost_usd = (costOverrideData.$ai_input_cost_usd ?? 0) + (costOverrideData.$ai_output_cost_usd ?? 0);
597
+ }
591
598
  }
592
599
 
593
600
  // The caller's own token counts override the SDK-derived ones further down, via the
@@ -631,7 +638,9 @@ const captureAiGeneration = async (client, options) => {
631
638
  $ai_input: safeInput,
632
639
  $ai_output_choices: safeOutput,
633
640
  $ai_http_status: httpStatus,
634
- $ai_input_tokens: usage.inputTokens ?? 0,
641
+ ...(usage.inputTokens !== undefined ? {
642
+ $ai_input_tokens: usage.inputTokens
643
+ } : {}),
635
644
  ...(usage.outputTokens !== undefined ? {
636
645
  $ai_output_tokens: usage.outputTokens
637
646
  } : {}),
@@ -749,10 +758,7 @@ class WrappedModels {
749
758
  latency,
750
759
  baseURL: 'https://generativelanguage.googleapis.com',
751
760
  modelParameters: getModelParams(params),
752
- usage: {
753
- inputTokens: 0,
754
- outputTokens: 0
755
- },
761
+ usage: {},
756
762
  error
757
763
  });
758
764
  throw error;
@@ -768,11 +774,10 @@ class WrappedModels {
768
774
  let firstTokenTime;
769
775
  let stopReason;
770
776
  let usage = {
771
- inputTokens: 0,
772
- outputTokens: 0,
773
777
  webSearchCount: 0,
774
778
  rawUsage: undefined
775
779
  };
780
+ let errored = false;
776
781
  try {
777
782
  const stream = await this.client.models.generateContentStream(geminiParams);
778
783
  for await (const chunk of stream) {
@@ -855,35 +860,8 @@ class WrappedModels {
855
860
  }
856
861
  yield chunk;
857
862
  }
858
- const latency = (Date.now() - startTime) / 1000;
859
- const timeToFirstToken = firstTokenTime !== undefined ? (firstTokenTime - startTime) / 1000 : undefined;
860
- const availableTools = extractAvailableToolCalls('gemini', geminiParams);
861
-
862
- // Format output similar to formatResponseGemini
863
- const output = accumulatedContent.length > 0 ? [{
864
- role: 'assistant',
865
- content: accumulatedContent
866
- }] : [];
867
- await captureAiGeneration(this.phClient, {
868
- ...posthogParams,
869
- model: geminiParams.model,
870
- provider: 'gemini',
871
- input: this.formatInputForPostHog(geminiParams),
872
- output,
873
- latency,
874
- timeToFirstToken,
875
- baseURL: 'https://generativelanguage.googleapis.com',
876
- modelParameters: getModelParams(params),
877
- httpStatus: 200,
878
- usage: {
879
- ...usage,
880
- webSearchCount: usage.webSearchCount,
881
- rawUsage: usage.rawUsage
882
- },
883
- stopReason,
884
- tools: availableTools
885
- });
886
863
  } catch (error) {
864
+ errored = true;
887
865
  const latency = (Date.now() - startTime) / 1000;
888
866
  await captureAiGeneration(this.phClient, {
889
867
  ...posthogParams,
@@ -894,13 +872,44 @@ class WrappedModels {
894
872
  latency,
895
873
  baseURL: 'https://generativelanguage.googleapis.com',
896
874
  modelParameters: getModelParams(params),
897
- usage: {
898
- inputTokens: 0,
899
- outputTokens: 0
900
- },
875
+ usage,
901
876
  error
902
877
  });
903
878
  throw error;
879
+ } finally {
880
+ // A consumer that stops iterating resumes the pending yield as a return,
881
+ // skipping both the loop tail and the catch. Only a finally runs then, so
882
+ // the success capture lives here to cover completion and cancellation.
883
+ if (!errored) {
884
+ const latency = (Date.now() - startTime) / 1000;
885
+ const timeToFirstToken = firstTokenTime !== undefined ? (firstTokenTime - startTime) / 1000 : undefined;
886
+ const availableTools = extractAvailableToolCalls('gemini', geminiParams);
887
+
888
+ // Format output similar to formatResponseGemini
889
+ const output = accumulatedContent.length > 0 ? [{
890
+ role: 'assistant',
891
+ content: accumulatedContent
892
+ }] : [];
893
+ await captureAiGeneration(this.phClient, {
894
+ ...posthogParams,
895
+ model: geminiParams.model,
896
+ provider: 'gemini',
897
+ input: this.formatInputForPostHog(geminiParams),
898
+ output,
899
+ latency,
900
+ timeToFirstToken,
901
+ baseURL: 'https://generativelanguage.googleapis.com',
902
+ modelParameters: getModelParams(params),
903
+ httpStatus: 200,
904
+ usage: {
905
+ ...usage,
906
+ webSearchCount: usage.webSearchCount,
907
+ rawUsage: usage.rawUsage
908
+ },
909
+ stopReason,
910
+ tools: availableTools
911
+ });
912
+ }
904
913
  }
905
914
  }
906
915
  async embedContent(params) {
@@ -941,9 +950,7 @@ class WrappedModels {
941
950
  latency,
942
951
  baseURL: 'https://generativelanguage.googleapis.com',
943
952
  modelParameters: getModelParams(params),
944
- usage: {
945
- inputTokens: 0
946
- },
953
+ usage: {},
947
954
  error
948
955
  });
949
956
  throw error;