@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.
@@ -338,7 +338,7 @@ function addDefaults(params) {
338
338
  };
339
339
  }
340
340
 
341
- var version = "8.9.0";
341
+ var version = "8.9.2";
342
342
 
343
343
  const DEFAULT_MAX_DEPTH = 3;
344
344
  const MAX_STACK_LINES = 20;
@@ -495,15 +495,22 @@ const captureAiGeneration = async (client, options) => {
495
495
  };
496
496
  }
497
497
  httpStatus = httpStatus ?? 200;
498
- let costOverrideData = {};
498
+
499
+ // A configured price applies only to a count the provider reported, so a call with no
500
+ // reported usage sends no cost instead of asserting $0. $ai_total_cost_usd sums the sides
501
+ // that were priced, which makes it the cost of the known side alone when the other side
502
+ // went unreported: a lower bound on the true total, not an assertion of it.
503
+ const costOverrideData = {};
499
504
  if (options.costOverride) {
500
- const inputCostUSD = (options.costOverride.inputCost ?? 0) * (usage.inputTokens ?? 0);
501
- const outputCostUSD = (options.costOverride.outputCost ?? 0) * (usage.outputTokens ?? 0);
502
- costOverrideData = {
503
- $ai_input_cost_usd: inputCostUSD,
504
- $ai_output_cost_usd: outputCostUSD,
505
- $ai_total_cost_usd: inputCostUSD + outputCostUSD
506
- };
505
+ if (usage.inputTokens !== undefined) {
506
+ costOverrideData.$ai_input_cost_usd = (options.costOverride.inputCost ?? 0) * usage.inputTokens;
507
+ }
508
+ if (usage.outputTokens !== undefined) {
509
+ costOverrideData.$ai_output_cost_usd = (options.costOverride.outputCost ?? 0) * usage.outputTokens;
510
+ }
511
+ if (Object.keys(costOverrideData).length > 0) {
512
+ costOverrideData.$ai_total_cost_usd = (costOverrideData.$ai_input_cost_usd ?? 0) + (costOverrideData.$ai_output_cost_usd ?? 0);
513
+ }
507
514
  }
508
515
 
509
516
  // The caller's own token counts override the SDK-derived ones further down, via the
@@ -547,7 +554,9 @@ const captureAiGeneration = async (client, options) => {
547
554
  $ai_input: safeInput,
548
555
  $ai_output_choices: safeOutput,
549
556
  $ai_http_status: httpStatus,
550
- $ai_input_tokens: usage.inputTokens ?? 0,
557
+ ...(usage.inputTokens !== undefined ? {
558
+ $ai_input_tokens: usage.inputTokens
559
+ } : {}),
551
560
  ...(usage.outputTokens !== undefined ? {
552
561
  $ai_output_tokens: usage.outputTokens
553
562
  } : {}),
@@ -597,14 +606,23 @@ const captureAiGeneration = async (client, options) => {
597
606
  }
598
607
  };
599
608
 
600
- function addRequestId(result, response, requestIdHeader) {
609
+ function addResponseIds(result, response, requestIdHeader, workspaceIdHeader) {
601
610
  if (!result || typeof result !== 'object' || Array.isArray(result)) {
602
611
  return result;
603
612
  }
604
- return Object.defineProperty(result, '_request_id', {
605
- value: response.headers.get(requestIdHeader),
606
- enumerable: false
607
- });
613
+ const properties = {
614
+ _request_id: {
615
+ value: response.headers.get(requestIdHeader),
616
+ enumerable: false
617
+ }
618
+ };
619
+ if (workspaceIdHeader) {
620
+ properties._workspace_id = {
621
+ value: response.headers.get(workspaceIdHeader),
622
+ enumerable: false
623
+ };
624
+ }
625
+ return Object.defineProperties(result, properties);
608
626
  }
609
627
  function getResponsePropsPromise(parentPromise) {
610
628
  const responsePromise = parentPromise.responsePromise;
@@ -613,7 +631,7 @@ function getResponsePropsPromise(parentPromise) {
613
631
  }
614
632
  return responsePromise;
615
633
  }
616
- function decorateProviderPromise(wrappedPromise, responsePropsPromise, requestIdHeader, preserveThenUnwrap) {
634
+ function decorateProviderPromise(wrappedPromise, responsePropsPromise, requestIdHeader, workspaceIdHeader, preserveThenUnwrap) {
617
635
  const providerPromise = wrappedPromise;
618
636
  if (responsePropsPromise) {
619
637
  providerPromise.asResponse = async () => (await responsePropsPromise).response;
@@ -622,7 +640,10 @@ function decorateProviderPromise(wrappedPromise, responsePropsPromise, requestId
622
640
  return {
623
641
  response: props.response,
624
642
  data,
625
- request_id: props.response.headers.get(requestIdHeader)
643
+ request_id: props.response.headers.get(requestIdHeader),
644
+ ...(workspaceIdHeader ? {
645
+ workspace_id: props.response.headers.get(workspaceIdHeader)
646
+ } : {})
626
647
  };
627
648
  };
628
649
  }
@@ -631,8 +652,8 @@ function decorateProviderPromise(wrappedPromise, responsePropsPromise, requestId
631
652
  if (!responsePropsPromise) {
632
653
  throw new Error('The provider promise response metadata is unavailable');
633
654
  }
634
- const transformedPromise = Promise.all([wrappedPromise, responsePropsPromise]).then(([data, props]) => addRequestId(transform(data, props), props.response, requestIdHeader));
635
- return decorateProviderPromise(transformedPromise, responsePropsPromise, requestIdHeader, true);
655
+ const transformedPromise = Promise.all([wrappedPromise, responsePropsPromise]).then(([data, props]) => addResponseIds(transform(data, props), props.response, requestIdHeader, workspaceIdHeader));
656
+ return decorateProviderPromise(transformedPromise, responsePropsPromise, requestIdHeader, workspaceIdHeader, true);
636
657
  };
637
658
  }
638
659
  return providerPromise;
@@ -648,7 +669,7 @@ function decorateProviderPromise(wrappedPromise, responsePropsPromise, requestId
648
669
  function preserveProviderPromise(parentPromise, wrappedPromise, options = {}) {
649
670
  const responsePropsPromise = getResponsePropsPromise(parentPromise);
650
671
  const preserveThenUnwrap = typeof parentPromise._thenUnwrap === 'function';
651
- const providerPromise = decorateProviderPromise(wrappedPromise, responsePropsPromise, options.requestIdHeader ?? 'x-request-id', preserveThenUnwrap);
672
+ const providerPromise = decorateProviderPromise(wrappedPromise, responsePropsPromise, options.requestIdHeader ?? 'x-request-id', options.workspaceIdHeader, preserveThenUnwrap);
652
673
  if (!responsePropsPromise) {
653
674
  const asResponse = parentPromise.asResponse?.bind(parentPromise);
654
675
  if (asResponse) {
@@ -915,10 +936,6 @@ class WrappedMessages extends AnthropicOriginal__default.default.Messages {
915
936
  let firstTokenTime;
916
937
  let stopReason;
917
938
  const usage = {
918
- inputTokens: 0,
919
- outputTokens: 0,
920
- cacheCreationInputTokens: 0,
921
- cacheReadInputTokens: 0,
922
939
  webSearchCount: 0
923
940
  };
924
941
  let rawUsage = {};
@@ -1062,19 +1079,21 @@ class WrappedMessages extends AnthropicOriginal__default.default.Messages {
1062
1079
  tools: availableTools
1063
1080
  });
1064
1081
  } catch (error) {
1082
+ // The final usage delta may never arrive; whatever raw usage did
1083
+ // still belongs on the event.
1084
+ if (Object.keys(rawUsage).length > 0) {
1085
+ usage.rawUsage = rawUsage;
1086
+ }
1065
1087
  await captureAiGeneration(this.phClient, {
1066
1088
  ...posthogParams,
1067
1089
  model: anthropicParams.model,
1068
1090
  provider: 'anthropic',
1069
1091
  input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams), this.phClient),
1070
1092
  output: [],
1071
- latency: 0,
1093
+ latency: (Date.now() - startTime) / 1000,
1072
1094
  baseURL: this.baseURL,
1073
1095
  modelParameters: getModelParams(body),
1074
- usage: {
1075
- inputTokens: 0,
1076
- outputTokens: 0
1077
- },
1096
+ usage,
1078
1097
  error: error
1079
1098
  });
1080
1099
  throw error;
@@ -1090,7 +1109,8 @@ class WrappedMessages extends AnthropicOriginal__default.default.Messages {
1090
1109
  return value;
1091
1110
  });
1092
1111
  return preserveProviderPromise(parentPromise, wrappedPromise, {
1093
- requestIdHeader: 'request-id'
1112
+ requestIdHeader: 'request-id',
1113
+ workspaceIdHeader: 'anthropic-workspace-id'
1094
1114
  });
1095
1115
  } else {
1096
1116
  const parentPromise = super.create(anthropicParams, options);
@@ -1128,20 +1148,18 @@ class WrappedMessages extends AnthropicOriginal__default.default.Messages {
1128
1148
  provider: 'anthropic',
1129
1149
  input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams), this.phClient),
1130
1150
  output: [],
1131
- latency: 0,
1151
+ latency: (Date.now() - startTime) / 1000,
1132
1152
  baseURL: this.baseURL,
1133
1153
  modelParameters: getModelParams(body),
1134
1154
  httpStatus: error?.status ? error.status : 500,
1135
- usage: {
1136
- inputTokens: 0,
1137
- outputTokens: 0
1138
- },
1155
+ usage: {},
1139
1156
  error: error
1140
1157
  });
1141
1158
  throw error;
1142
1159
  });
1143
1160
  return preserveProviderPromise(parentPromise, wrappedPromise, {
1144
- requestIdHeader: 'request-id'
1161
+ requestIdHeader: 'request-id',
1162
+ workspaceIdHeader: 'anthropic-workspace-id'
1145
1163
  });
1146
1164
  }
1147
1165
  }