@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.
@@ -330,7 +330,7 @@ function addDefaults(params) {
330
330
  };
331
331
  }
332
332
 
333
- var version = "8.9.0";
333
+ var version = "8.9.2";
334
334
 
335
335
  const DEFAULT_MAX_DEPTH = 3;
336
336
  const MAX_STACK_LINES = 20;
@@ -487,15 +487,22 @@ const captureAiGeneration = async (client, options) => {
487
487
  };
488
488
  }
489
489
  httpStatus = httpStatus ?? 200;
490
- let costOverrideData = {};
490
+
491
+ // A configured price applies only to a count the provider reported, so a call with no
492
+ // reported usage sends no cost instead of asserting $0. $ai_total_cost_usd sums the sides
493
+ // that were priced, which makes it the cost of the known side alone when the other side
494
+ // went unreported: a lower bound on the true total, not an assertion of it.
495
+ const costOverrideData = {};
491
496
  if (options.costOverride) {
492
- const inputCostUSD = (options.costOverride.inputCost ?? 0) * (usage.inputTokens ?? 0);
493
- const outputCostUSD = (options.costOverride.outputCost ?? 0) * (usage.outputTokens ?? 0);
494
- costOverrideData = {
495
- $ai_input_cost_usd: inputCostUSD,
496
- $ai_output_cost_usd: outputCostUSD,
497
- $ai_total_cost_usd: inputCostUSD + outputCostUSD
498
- };
497
+ if (usage.inputTokens !== undefined) {
498
+ costOverrideData.$ai_input_cost_usd = (options.costOverride.inputCost ?? 0) * usage.inputTokens;
499
+ }
500
+ if (usage.outputTokens !== undefined) {
501
+ costOverrideData.$ai_output_cost_usd = (options.costOverride.outputCost ?? 0) * usage.outputTokens;
502
+ }
503
+ if (Object.keys(costOverrideData).length > 0) {
504
+ costOverrideData.$ai_total_cost_usd = (costOverrideData.$ai_input_cost_usd ?? 0) + (costOverrideData.$ai_output_cost_usd ?? 0);
505
+ }
499
506
  }
500
507
 
501
508
  // The caller's own token counts override the SDK-derived ones further down, via the
@@ -539,7 +546,9 @@ const captureAiGeneration = async (client, options) => {
539
546
  $ai_input: safeInput,
540
547
  $ai_output_choices: safeOutput,
541
548
  $ai_http_status: httpStatus,
542
- $ai_input_tokens: usage.inputTokens ?? 0,
549
+ ...(usage.inputTokens !== undefined ? {
550
+ $ai_input_tokens: usage.inputTokens
551
+ } : {}),
543
552
  ...(usage.outputTokens !== undefined ? {
544
553
  $ai_output_tokens: usage.outputTokens
545
554
  } : {}),
@@ -589,14 +598,23 @@ const captureAiGeneration = async (client, options) => {
589
598
  }
590
599
  };
591
600
 
592
- function addRequestId(result, response, requestIdHeader) {
601
+ function addResponseIds(result, response, requestIdHeader, workspaceIdHeader) {
593
602
  if (!result || typeof result !== 'object' || Array.isArray(result)) {
594
603
  return result;
595
604
  }
596
- return Object.defineProperty(result, '_request_id', {
597
- value: response.headers.get(requestIdHeader),
598
- enumerable: false
599
- });
605
+ const properties = {
606
+ _request_id: {
607
+ value: response.headers.get(requestIdHeader),
608
+ enumerable: false
609
+ }
610
+ };
611
+ if (workspaceIdHeader) {
612
+ properties._workspace_id = {
613
+ value: response.headers.get(workspaceIdHeader),
614
+ enumerable: false
615
+ };
616
+ }
617
+ return Object.defineProperties(result, properties);
600
618
  }
601
619
  function getResponsePropsPromise(parentPromise) {
602
620
  const responsePromise = parentPromise.responsePromise;
@@ -605,7 +623,7 @@ function getResponsePropsPromise(parentPromise) {
605
623
  }
606
624
  return responsePromise;
607
625
  }
608
- function decorateProviderPromise(wrappedPromise, responsePropsPromise, requestIdHeader, preserveThenUnwrap) {
626
+ function decorateProviderPromise(wrappedPromise, responsePropsPromise, requestIdHeader, workspaceIdHeader, preserveThenUnwrap) {
609
627
  const providerPromise = wrappedPromise;
610
628
  if (responsePropsPromise) {
611
629
  providerPromise.asResponse = async () => (await responsePropsPromise).response;
@@ -614,7 +632,10 @@ function decorateProviderPromise(wrappedPromise, responsePropsPromise, requestId
614
632
  return {
615
633
  response: props.response,
616
634
  data,
617
- request_id: props.response.headers.get(requestIdHeader)
635
+ request_id: props.response.headers.get(requestIdHeader),
636
+ ...(workspaceIdHeader ? {
637
+ workspace_id: props.response.headers.get(workspaceIdHeader)
638
+ } : {})
618
639
  };
619
640
  };
620
641
  }
@@ -623,8 +644,8 @@ function decorateProviderPromise(wrappedPromise, responsePropsPromise, requestId
623
644
  if (!responsePropsPromise) {
624
645
  throw new Error('The provider promise response metadata is unavailable');
625
646
  }
626
- const transformedPromise = Promise.all([wrappedPromise, responsePropsPromise]).then(([data, props]) => addRequestId(transform(data, props), props.response, requestIdHeader));
627
- return decorateProviderPromise(transformedPromise, responsePropsPromise, requestIdHeader, true);
647
+ const transformedPromise = Promise.all([wrappedPromise, responsePropsPromise]).then(([data, props]) => addResponseIds(transform(data, props), props.response, requestIdHeader, workspaceIdHeader));
648
+ return decorateProviderPromise(transformedPromise, responsePropsPromise, requestIdHeader, workspaceIdHeader, true);
628
649
  };
629
650
  }
630
651
  return providerPromise;
@@ -640,7 +661,7 @@ function decorateProviderPromise(wrappedPromise, responsePropsPromise, requestId
640
661
  function preserveProviderPromise(parentPromise, wrappedPromise, options = {}) {
641
662
  const responsePropsPromise = getResponsePropsPromise(parentPromise);
642
663
  const preserveThenUnwrap = typeof parentPromise._thenUnwrap === 'function';
643
- const providerPromise = decorateProviderPromise(wrappedPromise, responsePropsPromise, options.requestIdHeader ?? 'x-request-id', preserveThenUnwrap);
664
+ const providerPromise = decorateProviderPromise(wrappedPromise, responsePropsPromise, options.requestIdHeader ?? 'x-request-id', options.workspaceIdHeader, preserveThenUnwrap);
644
665
  if (!responsePropsPromise) {
645
666
  const asResponse = parentPromise.asResponse?.bind(parentPromise);
646
667
  if (asResponse) {
@@ -907,10 +928,6 @@ class WrappedMessages extends AnthropicOriginal.Messages {
907
928
  let firstTokenTime;
908
929
  let stopReason;
909
930
  const usage = {
910
- inputTokens: 0,
911
- outputTokens: 0,
912
- cacheCreationInputTokens: 0,
913
- cacheReadInputTokens: 0,
914
931
  webSearchCount: 0
915
932
  };
916
933
  let rawUsage = {};
@@ -1054,19 +1071,21 @@ class WrappedMessages extends AnthropicOriginal.Messages {
1054
1071
  tools: availableTools
1055
1072
  });
1056
1073
  } catch (error) {
1074
+ // The final usage delta may never arrive; whatever raw usage did
1075
+ // still belongs on the event.
1076
+ if (Object.keys(rawUsage).length > 0) {
1077
+ usage.rawUsage = rawUsage;
1078
+ }
1057
1079
  await captureAiGeneration(this.phClient, {
1058
1080
  ...posthogParams,
1059
1081
  model: anthropicParams.model,
1060
1082
  provider: 'anthropic',
1061
1083
  input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams), this.phClient),
1062
1084
  output: [],
1063
- latency: 0,
1085
+ latency: (Date.now() - startTime) / 1000,
1064
1086
  baseURL: this.baseURL,
1065
1087
  modelParameters: getModelParams(body),
1066
- usage: {
1067
- inputTokens: 0,
1068
- outputTokens: 0
1069
- },
1088
+ usage,
1070
1089
  error: error
1071
1090
  });
1072
1091
  throw error;
@@ -1082,7 +1101,8 @@ class WrappedMessages extends AnthropicOriginal.Messages {
1082
1101
  return value;
1083
1102
  });
1084
1103
  return preserveProviderPromise(parentPromise, wrappedPromise, {
1085
- requestIdHeader: 'request-id'
1104
+ requestIdHeader: 'request-id',
1105
+ workspaceIdHeader: 'anthropic-workspace-id'
1086
1106
  });
1087
1107
  } else {
1088
1108
  const parentPromise = super.create(anthropicParams, options);
@@ -1120,20 +1140,18 @@ class WrappedMessages extends AnthropicOriginal.Messages {
1120
1140
  provider: 'anthropic',
1121
1141
  input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams), this.phClient),
1122
1142
  output: [],
1123
- latency: 0,
1143
+ latency: (Date.now() - startTime) / 1000,
1124
1144
  baseURL: this.baseURL,
1125
1145
  modelParameters: getModelParams(body),
1126
1146
  httpStatus: error?.status ? error.status : 500,
1127
- usage: {
1128
- inputTokens: 0,
1129
- outputTokens: 0
1130
- },
1147
+ usage: {},
1131
1148
  error: error
1132
1149
  });
1133
1150
  throw error;
1134
1151
  });
1135
1152
  return preserveProviderPromise(parentPromise, wrappedPromise, {
1136
- requestIdHeader: 'request-id'
1153
+ requestIdHeader: 'request-id',
1154
+ workspaceIdHeader: 'anthropic-workspace-id'
1137
1155
  });
1138
1156
  }
1139
1157
  }