@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.
@@ -581,7 +581,7 @@ function formatOpenAIResponsesInput(input, instructions) {
581
581
  return messages;
582
582
  }
583
583
 
584
- var version = "8.9.0";
584
+ var version = "8.9.2";
585
585
 
586
586
  const DEFAULT_MAX_DEPTH = 3;
587
587
  const MAX_STACK_LINES = 20;
@@ -738,15 +738,22 @@ const captureAiGeneration$1 = async (client, options) => {
738
738
  };
739
739
  }
740
740
  httpStatus = httpStatus ?? 200;
741
- let costOverrideData = {};
741
+
742
+ // A configured price applies only to a count the provider reported, so a call with no
743
+ // reported usage sends no cost instead of asserting $0. $ai_total_cost_usd sums the sides
744
+ // that were priced, which makes it the cost of the known side alone when the other side
745
+ // went unreported: a lower bound on the true total, not an assertion of it.
746
+ const costOverrideData = {};
742
747
  if (options.costOverride) {
743
- const inputCostUSD = (options.costOverride.inputCost ?? 0) * (usage.inputTokens ?? 0);
744
- const outputCostUSD = (options.costOverride.outputCost ?? 0) * (usage.outputTokens ?? 0);
745
- costOverrideData = {
746
- $ai_input_cost_usd: inputCostUSD,
747
- $ai_output_cost_usd: outputCostUSD,
748
- $ai_total_cost_usd: inputCostUSD + outputCostUSD
749
- };
748
+ if (usage.inputTokens !== undefined) {
749
+ costOverrideData.$ai_input_cost_usd = (options.costOverride.inputCost ?? 0) * usage.inputTokens;
750
+ }
751
+ if (usage.outputTokens !== undefined) {
752
+ costOverrideData.$ai_output_cost_usd = (options.costOverride.outputCost ?? 0) * usage.outputTokens;
753
+ }
754
+ if (Object.keys(costOverrideData).length > 0) {
755
+ costOverrideData.$ai_total_cost_usd = (costOverrideData.$ai_input_cost_usd ?? 0) + (costOverrideData.$ai_output_cost_usd ?? 0);
756
+ }
750
757
  }
751
758
 
752
759
  // The caller's own token counts override the SDK-derived ones further down, via the
@@ -790,7 +797,9 @@ const captureAiGeneration$1 = async (client, options) => {
790
797
  $ai_input: safeInput,
791
798
  $ai_output_choices: safeOutput,
792
799
  $ai_http_status: httpStatus,
793
- $ai_input_tokens: usage.inputTokens ?? 0,
800
+ ...(usage.inputTokens !== undefined ? {
801
+ $ai_input_tokens: usage.inputTokens
802
+ } : {}),
794
803
  ...(usage.outputTokens !== undefined ? {
795
804
  $ai_output_tokens: usage.outputTokens
796
805
  } : {}),
@@ -1021,14 +1030,23 @@ function wrapBackgroundResponseStream(stream, responseID, tracker, captureTermin
1021
1030
  return new streaming.Stream(() => inspectStream(), stream.controller);
1022
1031
  }
1023
1032
 
1024
- function addRequestId(result, response, requestIdHeader) {
1033
+ function addResponseIds(result, response, requestIdHeader, workspaceIdHeader) {
1025
1034
  if (!result || typeof result !== 'object' || Array.isArray(result)) {
1026
1035
  return result;
1027
1036
  }
1028
- return Object.defineProperty(result, '_request_id', {
1029
- value: response.headers.get(requestIdHeader),
1030
- enumerable: false
1031
- });
1037
+ const properties = {
1038
+ _request_id: {
1039
+ value: response.headers.get(requestIdHeader),
1040
+ enumerable: false
1041
+ }
1042
+ };
1043
+ if (workspaceIdHeader) {
1044
+ properties._workspace_id = {
1045
+ value: response.headers.get(workspaceIdHeader),
1046
+ enumerable: false
1047
+ };
1048
+ }
1049
+ return Object.defineProperties(result, properties);
1032
1050
  }
1033
1051
  function getResponsePropsPromise(parentPromise) {
1034
1052
  const responsePromise = parentPromise.responsePromise;
@@ -1037,7 +1055,7 @@ function getResponsePropsPromise(parentPromise) {
1037
1055
  }
1038
1056
  return responsePromise;
1039
1057
  }
1040
- function decorateProviderPromise(wrappedPromise, responsePropsPromise, requestIdHeader, preserveThenUnwrap) {
1058
+ function decorateProviderPromise(wrappedPromise, responsePropsPromise, requestIdHeader, workspaceIdHeader, preserveThenUnwrap) {
1041
1059
  const providerPromise = wrappedPromise;
1042
1060
  if (responsePropsPromise) {
1043
1061
  providerPromise.asResponse = async () => (await responsePropsPromise).response;
@@ -1046,7 +1064,10 @@ function decorateProviderPromise(wrappedPromise, responsePropsPromise, requestId
1046
1064
  return {
1047
1065
  response: props.response,
1048
1066
  data,
1049
- request_id: props.response.headers.get(requestIdHeader)
1067
+ request_id: props.response.headers.get(requestIdHeader),
1068
+ ...(workspaceIdHeader ? {
1069
+ workspace_id: props.response.headers.get(workspaceIdHeader)
1070
+ } : {})
1050
1071
  };
1051
1072
  };
1052
1073
  }
@@ -1055,8 +1076,8 @@ function decorateProviderPromise(wrappedPromise, responsePropsPromise, requestId
1055
1076
  if (!responsePropsPromise) {
1056
1077
  throw new Error('The provider promise response metadata is unavailable');
1057
1078
  }
1058
- const transformedPromise = Promise.all([wrappedPromise, responsePropsPromise]).then(([data, props]) => addRequestId(transform(data, props), props.response, requestIdHeader));
1059
- return decorateProviderPromise(transformedPromise, responsePropsPromise, requestIdHeader, true);
1079
+ const transformedPromise = Promise.all([wrappedPromise, responsePropsPromise]).then(([data, props]) => addResponseIds(transform(data, props), props.response, requestIdHeader, workspaceIdHeader));
1080
+ return decorateProviderPromise(transformedPromise, responsePropsPromise, requestIdHeader, workspaceIdHeader, true);
1060
1081
  };
1061
1082
  }
1062
1083
  return providerPromise;
@@ -1072,7 +1093,7 @@ function decorateProviderPromise(wrappedPromise, responsePropsPromise, requestId
1072
1093
  function preserveProviderPromise(parentPromise, wrappedPromise, options = {}) {
1073
1094
  const responsePropsPromise = getResponsePropsPromise(parentPromise);
1074
1095
  const preserveThenUnwrap = typeof parentPromise._thenUnwrap === 'function';
1075
- const providerPromise = decorateProviderPromise(wrappedPromise, responsePropsPromise, options.requestIdHeader ?? 'x-request-id', preserveThenUnwrap);
1096
+ const providerPromise = decorateProviderPromise(wrappedPromise, responsePropsPromise, options.requestIdHeader ?? 'x-request-id', options.workspaceIdHeader, preserveThenUnwrap);
1076
1097
  if (!responsePropsPromise) {
1077
1098
  const asResponse = parentPromise.asResponse?.bind(parentPromise);
1078
1099
  if (asResponse) {
@@ -1331,8 +1352,6 @@ function monitoredStreamTee(source, createStream) {
1331
1352
  class OpenAIChatStreamAccumulator {
1332
1353
  accumulatedContent = '';
1333
1354
  usage = {
1334
- inputTokens: 0,
1335
- outputTokens: 0,
1336
1355
  webSearchCount: 0
1337
1356
  };
1338
1357
  toolCalls = new Map();
@@ -1434,8 +1453,6 @@ class OpenAIChatStreamAccumulator {
1434
1453
  class OpenAIResponsesStreamAccumulator {
1435
1454
  output = [];
1436
1455
  usage = {
1437
- inputTokens: 0,
1438
- outputTokens: 0,
1439
1456
  webSearchCount: 0
1440
1457
  };
1441
1458
  consume(event, receivedAt = Date.now()) {
@@ -1544,20 +1561,17 @@ function buildChatSuccessOptions(context, result) {
1544
1561
  })
1545
1562
  };
1546
1563
  }
1547
- function buildChatErrorOptions(context, error, metadata = {}) {
1564
+ function buildChatErrorOptions(context, error, metadata) {
1548
1565
  return {
1549
1566
  ...context.monitoring,
1550
1567
  model: context.params.model,
1551
1568
  provider: context.provider,
1552
1569
  input: sanitizeOpenAI(context.params.messages, context.client),
1553
1570
  output: [],
1554
- latency: 0,
1571
+ latency: metadata.latency,
1555
1572
  baseURL: context.baseURL,
1556
1573
  modelParameters: getModelParams(context.modelParametersSource),
1557
- usage: {
1558
- inputTokens: 0,
1559
- outputTokens: 0
1560
- },
1574
+ usage: metadata.usage ?? {},
1561
1575
  completionId: metadata.completionId,
1562
1576
  providerMetadata: buildProviderMetadata({
1563
1577
  systemFingerprint: metadata.systemFingerprint
@@ -1607,21 +1621,18 @@ function buildBackgroundResponseOptions(context, response) {
1607
1621
  includeRequestId: true
1608
1622
  });
1609
1623
  }
1610
- function buildResponsesErrorOptions(context, error, completionId) {
1624
+ function buildResponsesErrorOptions(context, error, metadata) {
1611
1625
  return {
1612
1626
  ...context.monitoring,
1613
1627
  model: context.params.model,
1614
1628
  provider: context.provider,
1615
1629
  input: buildSanitizedResponsesInput(context),
1616
1630
  output: [],
1617
- latency: 0,
1631
+ latency: metadata.latency,
1618
1632
  baseURL: context.baseURL,
1619
1633
  modelParameters: getModelParams(context.modelParametersSource),
1620
- usage: {
1621
- inputTokens: 0,
1622
- outputTokens: 0
1623
- },
1624
- completionId,
1634
+ usage: metadata.usage ?? {},
1635
+ completionId: metadata.completionId,
1625
1636
  error
1626
1637
  };
1627
1638
  }
@@ -1643,7 +1654,7 @@ function buildEmbeddingSuccessOptions(context, usage, latency) {
1643
1654
  }
1644
1655
  };
1645
1656
  }
1646
- function buildEmbeddingErrorOptions(context, error) {
1657
+ function buildEmbeddingErrorOptions(context, error, latency) {
1647
1658
  return {
1648
1659
  eventType: AIEvent.Embedding,
1649
1660
  ...context.monitoring,
@@ -1651,12 +1662,10 @@ function buildEmbeddingErrorOptions(context, error) {
1651
1662
  provider: context.provider,
1652
1663
  input: withPrivacyMode(context.client, context.monitoring.privacyMode, context.params.input),
1653
1664
  output: null,
1654
- latency: 0,
1665
+ latency,
1655
1666
  baseURL: context.baseURL,
1656
1667
  modelParameters: getModelParams(context.modelParametersSource),
1657
- usage: {
1658
- inputTokens: 0
1659
- },
1668
+ usage: {},
1660
1669
  error
1661
1670
  };
1662
1671
  }
@@ -1735,7 +1744,9 @@ let WrappedCompletions$1 = class WrappedCompletions extends openai.AzureOpenAI.C
1735
1744
  modelParametersSource: body
1736
1745
  }, error, {
1737
1746
  completionId: accumulated.completionId,
1738
- systemFingerprint: accumulated.systemFingerprint
1747
+ systemFingerprint: accumulated.systemFingerprint,
1748
+ usage: accumulated.usage,
1749
+ latency: (Date.now() - startTime) / 1000
1739
1750
  }));
1740
1751
  throw error;
1741
1752
  }
@@ -1781,7 +1792,9 @@ let WrappedCompletions$1 = class WrappedCompletions extends openai.AzureOpenAI.C
1781
1792
  params: openAIParams,
1782
1793
  monitoring: posthogParams,
1783
1794
  modelParametersSource: body
1784
- }, error));
1795
+ }, error, {
1796
+ latency: (Date.now() - startTime) / 1000
1797
+ }));
1785
1798
  throw error;
1786
1799
  });
1787
1800
  return preserveProviderPromise(parentPromise, wrappedPromise);
@@ -1883,7 +1896,11 @@ let WrappedResponses$1 = class WrappedResponses extends openai.AzureOpenAI.Respo
1883
1896
  params: openAIParams,
1884
1897
  monitoring: posthogParams,
1885
1898
  modelParametersSource: body
1886
- }, error, accumulated.completionId));
1899
+ }, error, {
1900
+ completionId: accumulated.completionId,
1901
+ usage: accumulated.usage,
1902
+ latency: (Date.now() - startTime) / 1000
1903
+ }));
1887
1904
  throw error;
1888
1905
  }
1889
1906
  })().catch(() => {
@@ -1931,7 +1948,9 @@ let WrappedResponses$1 = class WrappedResponses extends openai.AzureOpenAI.Respo
1931
1948
  params: openAIParams,
1932
1949
  monitoring: posthogParams,
1933
1950
  modelParametersSource: body
1934
- }, error));
1951
+ }, error, {
1952
+ latency: (Date.now() - startTime) / 1000
1953
+ }));
1935
1954
  throw error;
1936
1955
  });
1937
1956
  return preserveProviderPromise(parentPromise, wrappedPromise);
@@ -2023,7 +2042,9 @@ let WrappedResponses$1 = class WrappedResponses extends openai.AzureOpenAI.Respo
2023
2042
  params: openAIParams,
2024
2043
  monitoring: posthogParams,
2025
2044
  modelParametersSource: body
2026
- }, error));
2045
+ }, error, {
2046
+ latency: (Date.now() - startTime) / 1000
2047
+ }));
2027
2048
  throw error;
2028
2049
  });
2029
2050
  return preserveProviderPromise(parentPromise, wrappedPromise);
@@ -2060,7 +2081,7 @@ let WrappedEmbeddings$1 = class WrappedEmbeddings extends openai.AzureOpenAI.Emb
2060
2081
  params: openAIParams,
2061
2082
  monitoring: posthogParams,
2062
2083
  modelParametersSource: body
2063
- }, error));
2084
+ }, error, (Date.now() - startTime) / 1000));
2064
2085
  throw error;
2065
2086
  });
2066
2087
  return preserveProviderPromise(parentPromise, wrappedPromise);
@@ -2148,7 +2169,9 @@ class WrappedCompletions extends Completions {
2148
2169
  modelParametersSource: body
2149
2170
  }, error, {
2150
2171
  completionId: accumulated.completionId,
2151
- systemFingerprint: accumulated.systemFingerprint
2172
+ systemFingerprint: accumulated.systemFingerprint,
2173
+ usage: accumulated.usage,
2174
+ latency: (Date.now() - startTime) / 1000
2152
2175
  }));
2153
2176
  throw error;
2154
2177
  }
@@ -2194,7 +2217,9 @@ class WrappedCompletions extends Completions {
2194
2217
  params: openAIParams,
2195
2218
  monitoring: posthogParams,
2196
2219
  modelParametersSource: body
2197
- }, error));
2220
+ }, error, {
2221
+ latency: (Date.now() - startTime) / 1000
2222
+ }));
2198
2223
  throw error;
2199
2224
  });
2200
2225
  return preserveProviderPromise(parentPromise, wrappedPromise);
@@ -2296,7 +2321,11 @@ class WrappedResponses extends Responses {
2296
2321
  params: openAIParams,
2297
2322
  monitoring: posthogParams,
2298
2323
  modelParametersSource: body
2299
- }, error, accumulated.completionId));
2324
+ }, error, {
2325
+ completionId: accumulated.completionId,
2326
+ usage: accumulated.usage,
2327
+ latency: (Date.now() - startTime) / 1000
2328
+ }));
2300
2329
  throw error;
2301
2330
  }
2302
2331
  })().catch(() => {
@@ -2344,7 +2373,9 @@ class WrappedResponses extends Responses {
2344
2373
  params: openAIParams,
2345
2374
  monitoring: posthogParams,
2346
2375
  modelParametersSource: body
2347
- }, error));
2376
+ }, error, {
2377
+ latency: (Date.now() - startTime) / 1000
2378
+ }));
2348
2379
  throw error;
2349
2380
  });
2350
2381
  return preserveProviderPromise(parentPromise, wrappedPromise);
@@ -2436,7 +2467,9 @@ class WrappedResponses extends Responses {
2436
2467
  params: openAIParams,
2437
2468
  monitoring: posthogParams,
2438
2469
  modelParametersSource: body
2439
- }, error));
2470
+ }, error, {
2471
+ latency: (Date.now() - startTime) / 1000
2472
+ }));
2440
2473
  throw error;
2441
2474
  });
2442
2475
  return preserveProviderPromise(parentPromise, wrappedPromise);
@@ -2473,7 +2506,7 @@ class WrappedEmbeddings extends Embeddings {
2473
2506
  params: openAIParams,
2474
2507
  monitoring: posthogParams,
2475
2508
  modelParametersSource: body
2476
- }, error));
2509
+ }, error, (Date.now() - startTime) / 1000));
2477
2510
  throw error;
2478
2511
  });
2479
2512
  return preserveProviderPromise(parentPromise, wrappedPromise);
@@ -2519,13 +2552,10 @@ class WrappedTranscriptions extends Transcriptions {
2519
2552
  if (Symbol.asyncIterator in value) {
2520
2553
  const [stream1, stream2] = monitoredStreamTee(value, (iterator, controller) => new streaming.Stream(iterator, controller));
2521
2554
  (async () => {
2555
+ let usage = {};
2522
2556
  try {
2523
2557
  let finalContent = '';
2524
2558
  let firstTokenTime;
2525
- let usage = {
2526
- inputTokens: 0,
2527
- outputTokens: 0
2528
- };
2529
2559
  const doneEvent = 'transcript.text.done';
2530
2560
  for await (const chunk of stream1) {
2531
2561
  // Track first token on text delta events
@@ -2567,13 +2597,10 @@ class WrappedTranscriptions extends Transcriptions {
2567
2597
  provider: 'openai',
2568
2598
  input: openAIParams.prompt,
2569
2599
  output: [],
2570
- latency: 0,
2600
+ latency: (Date.now() - startTime) / 1000,
2571
2601
  baseURL: this.baseURL,
2572
2602
  modelParameters: getModelParams(body),
2573
- usage: {
2574
- inputTokens: 0,
2575
- outputTokens: 0
2576
- },
2603
+ usage,
2577
2604
  error
2578
2605
  });
2579
2606
  throw error;
@@ -2616,13 +2643,10 @@ class WrappedTranscriptions extends Transcriptions {
2616
2643
  provider: 'openai',
2617
2644
  input: openAIParams.prompt,
2618
2645
  output: [],
2619
- latency: 0,
2646
+ latency: (Date.now() - startTime) / 1000,
2620
2647
  baseURL: this.baseURL,
2621
2648
  modelParameters: getModelParams(body),
2622
- usage: {
2623
- inputTokens: 0,
2624
- outputTokens: 0
2625
- },
2649
+ usage: {},
2626
2650
  error
2627
2651
  });
2628
2652
  throw error;