@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.
@@ -5,6 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var openai = require('openai');
6
6
  var uuid = require('uuid');
7
7
  var core = require('@posthog/core');
8
+ var streaming = require('openai/streaming');
8
9
 
9
10
  // Type guards for safer type checking
10
11
 
@@ -537,7 +538,7 @@ function formatOpenAIResponsesInput(input, instructions) {
537
538
  return messages;
538
539
  }
539
540
 
540
- var version = "8.6.2";
541
+ var version = "8.6.4";
541
542
 
542
543
  const DEFAULT_MAX_DEPTH = 3;
543
544
  const MAX_STACK_LINES = 20;
@@ -648,125 +649,133 @@ const warnIfPostHogAiGateway = baseURL => {
648
649
  * so callers can re-throw the original error reference safely.
649
650
  */
650
651
  const captureAiGeneration$1 = async (client, options) => {
651
- if (!client.capture) {
652
- return;
653
- }
654
- warnIfPostHogAiGateway(options.baseURL);
655
- const traceId = options.traceId ?? uuid.v4();
656
- const eventType = options.eventType ?? AIEvent.Generation;
657
- const privacyMode = options.privacyMode ?? false;
658
- const usage = options.usage ?? {};
659
-
660
- // Check privacy before reading or traversing input/output. Besides avoiding
661
- // needless work, this ensures hostile getters/proxies cannot observe a value
662
- // that the caller explicitly requested us to redact.
663
- const shouldRedact = withPrivacyMode(client, privacyMode, false) === null;
664
- const safeInput = shouldRedact ? null : core.toJsonSafeValue(options.input);
665
- const safeOutput = shouldRedact ? null : core.toJsonSafeValue(options.output);
666
- let httpStatus = options.httpStatus;
667
- let errorData = {};
668
- if (options.error) {
669
- if (httpStatus === undefined) {
670
- if (typeof options.error === 'object' && 'status' in options.error && typeof options.error.status === 'number') {
671
- httpStatus = options.error.status;
672
- } else {
673
- httpStatus = 500;
674
- }
652
+ try {
653
+ if (!client.capture) {
654
+ return;
675
655
  }
676
- let exceptionId;
677
- if (client.options?.enableExceptionAutocapture) {
678
- exceptionId = core.uuidv7();
679
- client.captureException(options.error, undefined, {
680
- $ai_trace_id: traceId
681
- }, exceptionId);
682
- if (typeof options.error === 'object') {
683
- options.error.__posthog_previously_captured_error = true;
656
+ warnIfPostHogAiGateway(options.baseURL);
657
+ const traceId = options.traceId ?? uuid.v4();
658
+ const eventType = options.eventType ?? AIEvent.Generation;
659
+ const privacyMode = options.privacyMode ?? false;
660
+ const usage = options.usage ?? {};
661
+
662
+ // Check privacy before reading or traversing input/output. Besides avoiding
663
+ // needless work, this ensures hostile getters/proxies cannot observe a value
664
+ // that the caller explicitly requested us to redact.
665
+ const shouldRedact = withPrivacyMode(client, privacyMode, false) === null;
666
+ const safeInput = shouldRedact ? null : core.toJsonSafeValue(options.input);
667
+ const safeOutput = shouldRedact ? null : core.toJsonSafeValue(options.output);
668
+ let httpStatus = options.httpStatus;
669
+ let errorData = {};
670
+ if (options.error) {
671
+ if (httpStatus === undefined) {
672
+ if (typeof options.error === 'object' && 'status' in options.error && typeof options.error.status === 'number') {
673
+ httpStatus = options.error.status;
674
+ } else if (typeof options.error === 'object' && 'statusCode' in options.error && typeof options.error.statusCode === 'number') {
675
+ httpStatus = options.error.statusCode;
676
+ } else {
677
+ httpStatus = 500;
678
+ }
684
679
  }
680
+ let exceptionId;
681
+ if (client.options?.enableExceptionAutocapture) {
682
+ exceptionId = core.uuidv7();
683
+ client.captureException(options.error, undefined, {
684
+ $ai_trace_id: traceId
685
+ }, exceptionId);
686
+ if (typeof options.error === 'object') {
687
+ ;
688
+ options.error.__posthog_previously_captured_error = true;
689
+ }
690
+ }
691
+ errorData = {
692
+ $ai_is_error: true,
693
+ $ai_error: stringifyError(options.error),
694
+ $exception_event_id: exceptionId
695
+ };
685
696
  }
686
- errorData = {
687
- $ai_is_error: true,
688
- $ai_error: stringifyError(options.error),
689
- $exception_event_id: exceptionId
697
+ httpStatus = httpStatus ?? 200;
698
+ let costOverrideData = {};
699
+ if (options.costOverride) {
700
+ const inputCostUSD = (options.costOverride.inputCost ?? 0) * (usage.inputTokens ?? 0);
701
+ const outputCostUSD = (options.costOverride.outputCost ?? 0) * (usage.outputTokens ?? 0);
702
+ costOverrideData = {
703
+ $ai_input_cost_usd: inputCostUSD,
704
+ $ai_output_cost_usd: outputCostUSD,
705
+ $ai_total_cost_usd: inputCostUSD + outputCostUSD
706
+ };
707
+ }
708
+ const additionalTokenValues = {
709
+ ...(usage.reasoningTokens ? {
710
+ $ai_reasoning_tokens: usage.reasoningTokens
711
+ } : {}),
712
+ ...(usage.cacheReadInputTokens ? {
713
+ $ai_cache_read_input_tokens: usage.cacheReadInputTokens
714
+ } : {}),
715
+ ...(usage.cacheCreationInputTokens ? {
716
+ $ai_cache_creation_input_tokens: usage.cacheCreationInputTokens
717
+ } : {}),
718
+ ...(usage.webSearchCount ? {
719
+ $ai_web_search_count: usage.webSearchCount
720
+ } : {}),
721
+ ...(usage.rawUsage ? {
722
+ $ai_usage: usage.rawUsage
723
+ } : {})
690
724
  };
691
- }
692
- httpStatus = httpStatus ?? 200;
693
- let costOverrideData = {};
694
- if (options.costOverride) {
695
- const inputCostUSD = (options.costOverride.inputCost ?? 0) * (usage.inputTokens ?? 0);
696
- const outputCostUSD = (options.costOverride.outputCost ?? 0) * (usage.outputTokens ?? 0);
697
- costOverrideData = {
698
- $ai_input_cost_usd: inputCostUSD,
699
- $ai_output_cost_usd: outputCostUSD,
700
- $ai_total_cost_usd: inputCostUSD + outputCostUSD
725
+ const properties = {
726
+ $ai_lib: 'posthog-ai',
727
+ $ai_lib_version: version,
728
+ $ai_provider: options.providerOverride ?? options.provider,
729
+ $ai_model: options.modelOverride ?? options.model,
730
+ $ai_model_parameters: options.modelParameters ?? {},
731
+ $ai_input: safeInput,
732
+ $ai_output_choices: safeOutput,
733
+ $ai_http_status: httpStatus,
734
+ $ai_input_tokens: usage.inputTokens ?? 0,
735
+ ...(usage.outputTokens !== undefined ? {
736
+ $ai_output_tokens: usage.outputTokens
737
+ } : {}),
738
+ ...additionalTokenValues,
739
+ $ai_latency: options.latency ?? 0,
740
+ ...(options.timeToFirstToken !== undefined ? {
741
+ $ai_time_to_first_token: options.timeToFirstToken
742
+ } : {}),
743
+ $ai_trace_id: traceId,
744
+ $ai_base_url: options.baseURL ?? '',
745
+ ...options.properties,
746
+ $ai_tokens_source: getTokensSource(options.properties),
747
+ ...(options.distinctId ? {} : {
748
+ $process_person_profile: false
749
+ }),
750
+ ...(options.stopReason ? {
751
+ $ai_stop_reason: options.stopReason
752
+ } : {}),
753
+ ...(options.tools ? {
754
+ $ai_tools: options.tools
755
+ } : {}),
756
+ ...(options.completionId ? {
757
+ $ai_completion_id: options.completionId
758
+ } : {}),
759
+ ...(options.providerMetadata && Object.keys(options.providerMetadata).length > 0 ? {
760
+ $ai_provider_metadata: options.providerMetadata
761
+ } : {}),
762
+ ...errorData,
763
+ ...costOverrideData
701
764
  };
702
- }
703
- const additionalTokenValues = {
704
- ...(usage.reasoningTokens ? {
705
- $ai_reasoning_tokens: usage.reasoningTokens
706
- } : {}),
707
- ...(usage.cacheReadInputTokens ? {
708
- $ai_cache_read_input_tokens: usage.cacheReadInputTokens
709
- } : {}),
710
- ...(usage.cacheCreationInputTokens ? {
711
- $ai_cache_creation_input_tokens: usage.cacheCreationInputTokens
712
- } : {}),
713
- ...(usage.webSearchCount ? {
714
- $ai_web_search_count: usage.webSearchCount
715
- } : {}),
716
- ...(usage.rawUsage ? {
717
- $ai_usage: usage.rawUsage
718
- } : {})
719
- };
720
- const properties = {
721
- $ai_lib: 'posthog-ai',
722
- $ai_lib_version: version,
723
- $ai_provider: options.providerOverride ?? options.provider,
724
- $ai_model: options.modelOverride ?? options.model,
725
- $ai_model_parameters: options.modelParameters ?? {},
726
- $ai_input: safeInput,
727
- $ai_output_choices: safeOutput,
728
- $ai_http_status: httpStatus,
729
- $ai_input_tokens: usage.inputTokens ?? 0,
730
- ...(usage.outputTokens !== undefined ? {
731
- $ai_output_tokens: usage.outputTokens
732
- } : {}),
733
- ...additionalTokenValues,
734
- $ai_latency: options.latency ?? 0,
735
- ...(options.timeToFirstToken !== undefined ? {
736
- $ai_time_to_first_token: options.timeToFirstToken
737
- } : {}),
738
- $ai_trace_id: traceId,
739
- $ai_base_url: options.baseURL ?? '',
740
- ...options.properties,
741
- $ai_tokens_source: getTokensSource(options.properties),
742
- ...(options.distinctId ? {} : {
743
- $process_person_profile: false
744
- }),
745
- ...(options.stopReason ? {
746
- $ai_stop_reason: options.stopReason
747
- } : {}),
748
- ...(options.tools ? {
749
- $ai_tools: options.tools
750
- } : {}),
751
- ...(options.completionId ? {
752
- $ai_completion_id: options.completionId
753
- } : {}),
754
- ...(options.providerMetadata && Object.keys(options.providerMetadata).length > 0 ? {
755
- $ai_provider_metadata: options.providerMetadata
756
- } : {}),
757
- ...errorData,
758
- ...costOverrideData
759
- };
760
- const event = {
761
- distinctId: options.distinctId ?? traceId,
762
- event: eventType,
763
- properties,
764
- groups: options.groups
765
- };
766
- if (options.captureImmediate) {
767
- await client.captureImmediate(event);
768
- } else {
769
- client.capture(event);
765
+ const event = {
766
+ distinctId: options.distinctId ?? traceId,
767
+ event: eventType,
768
+ properties,
769
+ groups: options.groups
770
+ };
771
+ if (options.captureImmediate) {
772
+ await client.captureImmediate(event);
773
+ } else {
774
+ client.capture(event);
775
+ }
776
+ } catch (error) {
777
+ // Telemetry failures must never affect the instrumented provider call.
778
+ console.warn('[PostHog AI] Failed to capture generation telemetry:', error);
770
779
  }
771
780
  };
772
781
 
@@ -843,6 +852,312 @@ function buildProviderMetadata(fields) {
843
852
  return Object.keys(metadata).length > 0 ? metadata : undefined;
844
853
  }
845
854
 
855
+ function addRequestId(result, response, requestIdHeader) {
856
+ if (!result || typeof result !== 'object' || Array.isArray(result)) {
857
+ return result;
858
+ }
859
+ return Object.defineProperty(result, '_request_id', {
860
+ value: response.headers.get(requestIdHeader),
861
+ enumerable: false
862
+ });
863
+ }
864
+ function getResponsePropsPromise(parentPromise) {
865
+ const responsePromise = parentPromise.responsePromise;
866
+ if (!responsePromise || typeof responsePromise.then !== 'function') {
867
+ return undefined;
868
+ }
869
+ return responsePromise;
870
+ }
871
+ function decorateProviderPromise(wrappedPromise, responsePropsPromise, requestIdHeader, preserveThenUnwrap) {
872
+ const providerPromise = wrappedPromise;
873
+ if (responsePropsPromise) {
874
+ providerPromise.asResponse = async () => (await responsePropsPromise).response;
875
+ providerPromise.withResponse = async () => {
876
+ const [props, data] = await Promise.all([responsePropsPromise, wrappedPromise]);
877
+ return {
878
+ response: props.response,
879
+ data,
880
+ request_id: props.response.headers.get(requestIdHeader)
881
+ };
882
+ };
883
+ }
884
+ if (preserveThenUnwrap) {
885
+ providerPromise._thenUnwrap = transform => {
886
+ if (!responsePropsPromise) {
887
+ throw new Error('The provider promise response metadata is unavailable');
888
+ }
889
+ const transformedPromise = Promise.all([wrappedPromise, responsePropsPromise]).then(([data, props]) => addRequestId(transform(data, props), props.response, requestIdHeader));
890
+ return decorateProviderPromise(transformedPromise, responsePropsPromise, requestIdHeader, true);
891
+ };
892
+ }
893
+ return providerPromise;
894
+ }
895
+
896
+ /**
897
+ * Keep the provider SDK helpers on a promise whose resolved value is instrumented.
898
+ * OpenAI's parse helpers compose create calls through `_thenUnwrap`, while both
899
+ * OpenAI and Anthropic expose the raw response through `asResponse` and
900
+ * `withResponse`.
901
+ */
902
+
903
+ function preserveProviderPromise(parentPromise, wrappedPromise, options = {}) {
904
+ const responsePropsPromise = getResponsePropsPromise(parentPromise);
905
+ const preserveThenUnwrap = typeof parentPromise._thenUnwrap === 'function';
906
+ const providerPromise = decorateProviderPromise(wrappedPromise, responsePropsPromise, options.requestIdHeader ?? 'x-request-id', preserveThenUnwrap);
907
+ if (!responsePropsPromise) {
908
+ const asResponse = parentPromise.asResponse?.bind(parentPromise);
909
+ if (asResponse) {
910
+ providerPromise.asResponse = asResponse;
911
+ }
912
+ const withResponse = parentPromise.withResponse?.bind(parentPromise);
913
+ if (withResponse) {
914
+ providerPromise.withResponse = async () => {
915
+ const [response, data] = await Promise.all([withResponse(), wrappedPromise]);
916
+ return {
917
+ ...response,
918
+ data
919
+ };
920
+ };
921
+ }
922
+ }
923
+ return providerPromise;
924
+ }
925
+
926
+ /**
927
+ * OpenAI's `Responses.parse` dispatches through `this._client.responses.create`.
928
+ * Temporarily use the provider's original `create` implementation so parsing a
929
+ * wrapped response does not capture the same request twice.
930
+ */
931
+ function callWithOriginalCreate(resource, originalCreate, callback) {
932
+ const resourceRecord = resource;
933
+ const hadOwnCreate = Object.prototype.hasOwnProperty.call(resource, 'create');
934
+ const wrappedCreate = resourceRecord['create'];
935
+ resourceRecord['create'] = originalCreate;
936
+ try {
937
+ return callback();
938
+ } finally {
939
+ if (hadOwnCreate) {
940
+ resourceRecord['create'] = wrappedCreate;
941
+ } else {
942
+ delete resourceRecord['create'];
943
+ }
944
+ }
945
+ }
946
+
947
+ /**
948
+ * Splits an SDK stream into a monitoring branch and a caller branch without
949
+ * allowing either branch to read ahead of the other. Unlike the SDKs' `tee()`
950
+ * implementations, this keeps at most one result in flight and makes caller
951
+ * cancellation terminate the monitoring branch and the source iterator.
952
+ */
953
+ function monitoredStreamTee(source, createStream) {
954
+ const controller = source.controller ?? new AbortController();
955
+ const sourceIterator = source[Symbol.asyncIterator]();
956
+ const callerQueue = [];
957
+ let monitorPending;
958
+ let monitorActive = true;
959
+ let operationInFlight = false;
960
+ let terminalResult;
961
+ let bufferedMonitorResult;
962
+ let terminalError;
963
+ let hasTerminalError = false;
964
+ let cancellationPromise;
965
+ let abortListener;
966
+ const removeAbortListener = () => {
967
+ if (abortListener) {
968
+ controller.signal.removeEventListener('abort', abortListener);
969
+ abortListener = undefined;
970
+ }
971
+ };
972
+ const settleMonitorTerminal = () => {
973
+ if (!monitorPending) {
974
+ return;
975
+ }
976
+ const pending = monitorPending;
977
+ monitorPending = undefined;
978
+ if (hasTerminalError) {
979
+ pending.reject(terminalError);
980
+ } else if (terminalResult) {
981
+ pending.resolve(terminalResult);
982
+ }
983
+ };
984
+ const settleCallersTerminal = () => {
985
+ while (callerQueue.length > 0) {
986
+ const pending = callerQueue.shift();
987
+ if (hasTerminalError) {
988
+ pending.reject(terminalError);
989
+ } else if (terminalResult) {
990
+ pending.resolve(terminalResult);
991
+ }
992
+ }
993
+ };
994
+ const pump = () => {
995
+ if (operationInFlight || callerQueue.length === 0 || monitorActive && !monitorPending) {
996
+ return;
997
+ }
998
+ const pendingCaller = callerQueue.shift();
999
+ const pendingMonitor = monitorPending;
1000
+ monitorPending = undefined;
1001
+ operationInFlight = true;
1002
+ void sourceIterator.next().then(result => {
1003
+ operationInFlight = false;
1004
+ if (result.done) {
1005
+ terminalResult = result;
1006
+ removeAbortListener();
1007
+ }
1008
+ pendingCaller.resolve(result);
1009
+ pendingMonitor?.resolve(result);
1010
+ if (result.done) {
1011
+ settleCallersTerminal();
1012
+ } else {
1013
+ pump();
1014
+ }
1015
+ }, error => {
1016
+ operationInFlight = false;
1017
+ terminalError = error;
1018
+ hasTerminalError = true;
1019
+ removeAbortListener();
1020
+ pendingCaller.reject(error);
1021
+ pendingMonitor?.reject(error);
1022
+ settleCallersTerminal();
1023
+ });
1024
+ };
1025
+ const monitoringStream = {
1026
+ [Symbol.asyncIterator]() {
1027
+ return {
1028
+ next: () => {
1029
+ if (hasTerminalError) {
1030
+ return Promise.reject(terminalError);
1031
+ }
1032
+ if (terminalResult) {
1033
+ return Promise.resolve(terminalResult);
1034
+ }
1035
+ if (bufferedMonitorResult) {
1036
+ const result = bufferedMonitorResult;
1037
+ bufferedMonitorResult = undefined;
1038
+ return Promise.resolve(result);
1039
+ }
1040
+ return new Promise((resolve, reject) => {
1041
+ monitorPending = {
1042
+ resolve,
1043
+ reject
1044
+ };
1045
+ pump();
1046
+ });
1047
+ },
1048
+ return: async value => {
1049
+ monitorActive = false;
1050
+ monitorPending = undefined;
1051
+ pump();
1052
+ return {
1053
+ done: true,
1054
+ value: value
1055
+ };
1056
+ }
1057
+ };
1058
+ }
1059
+ };
1060
+ const cancelSource = value => {
1061
+ if (cancellationPromise) {
1062
+ return cancellationPromise;
1063
+ }
1064
+ removeAbortListener();
1065
+ if (!controller.signal.aborted) {
1066
+ controller.abort();
1067
+ }
1068
+ cancellationPromise = (async () => {
1069
+ try {
1070
+ const defaultResult = {
1071
+ done: true,
1072
+ value
1073
+ };
1074
+ const result = sourceIterator.return ? await sourceIterator.return(value) : defaultResult;
1075
+ if (result.done) {
1076
+ terminalResult = result;
1077
+ removeAbortListener();
1078
+ settleMonitorTerminal();
1079
+ settleCallersTerminal();
1080
+ } else if (monitorPending) {
1081
+ monitorPending.resolve(result);
1082
+ monitorPending = undefined;
1083
+ cancellationPromise = undefined;
1084
+ } else {
1085
+ bufferedMonitorResult = result;
1086
+ cancellationPromise = undefined;
1087
+ }
1088
+ return result;
1089
+ } catch (error) {
1090
+ terminalError = error;
1091
+ hasTerminalError = true;
1092
+ removeAbortListener();
1093
+ settleMonitorTerminal();
1094
+ settleCallersTerminal();
1095
+ throw error;
1096
+ }
1097
+ })();
1098
+ // An AbortController cancellation has no caller awaiting this promise.
1099
+ void cancellationPromise.catch(() => undefined);
1100
+ return cancellationPromise;
1101
+ };
1102
+ abortListener = () => {
1103
+ void cancelSource();
1104
+ };
1105
+ if (controller.signal.aborted) {
1106
+ abortListener();
1107
+ } else {
1108
+ controller.signal.addEventListener('abort', abortListener, {
1109
+ once: true
1110
+ });
1111
+ }
1112
+ const callerStream = createStream(() => ({
1113
+ next: () => {
1114
+ if (hasTerminalError) {
1115
+ return Promise.reject(terminalError);
1116
+ }
1117
+ if (terminalResult) {
1118
+ return Promise.resolve(terminalResult);
1119
+ }
1120
+ return new Promise((resolve, reject) => {
1121
+ callerQueue.push({
1122
+ resolve,
1123
+ reject
1124
+ });
1125
+ pump();
1126
+ });
1127
+ },
1128
+ return: value => cancelSource(value),
1129
+ throw: async error => {
1130
+ if (!sourceIterator.throw) {
1131
+ await cancelSource();
1132
+ throw error;
1133
+ }
1134
+ try {
1135
+ const result = await sourceIterator.throw(error);
1136
+ if (result.done) {
1137
+ terminalResult = result;
1138
+ removeAbortListener();
1139
+ settleCallersTerminal();
1140
+ }
1141
+ if (monitorPending) {
1142
+ monitorPending.resolve(result);
1143
+ monitorPending = undefined;
1144
+ } else {
1145
+ bufferedMonitorResult = result;
1146
+ }
1147
+ return result;
1148
+ } catch (sourceError) {
1149
+ terminalError = sourceError;
1150
+ hasTerminalError = true;
1151
+ removeAbortListener();
1152
+ settleMonitorTerminal();
1153
+ settleCallersTerminal();
1154
+ throw sourceError;
1155
+ }
1156
+ }
1157
+ }), controller);
1158
+ return [monitoringStream, callerStream];
1159
+ }
1160
+
846
1161
  class PostHogAzureOpenAI extends openai.AzureOpenAI {
847
1162
  constructor(config) {
848
1163
  const {
@@ -884,9 +1199,9 @@ let WrappedCompletions$1 = class WrappedCompletions extends openai.AzureOpenAI.C
884
1199
  const startTime = Date.now();
885
1200
  const parentPromise = super.create(openAIParams, options);
886
1201
  if (openAIParams.stream) {
887
- return parentPromise.then(value => {
888
- if ('tee' in value) {
889
- const [stream1, stream2] = value.tee();
1202
+ const wrappedPromise = parentPromise.then(value => {
1203
+ if (Symbol.asyncIterator in value) {
1204
+ const [stream1, stream2] = monitoredStreamTee(value, (iterator, controller) => new streaming.Stream(iterator, controller));
890
1205
  (async () => {
891
1206
  // Hoisted so the catch block can surface whatever was accumulated
892
1207
  // from the streamed chunks before the failure.
@@ -1062,6 +1377,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends openai.AzureOpenAI.C
1062
1377
  }
1063
1378
  return value;
1064
1379
  });
1380
+ return preserveProviderPromise(parentPromise, wrappedPromise);
1065
1381
  } else {
1066
1382
  const wrappedPromise = parentPromise.then(async result => {
1067
1383
  if ('choices' in result) {
@@ -1110,7 +1426,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends openai.AzureOpenAI.C
1110
1426
  });
1111
1427
  throw error;
1112
1428
  });
1113
- return wrappedPromise;
1429
+ return preserveProviderPromise(parentPromise, wrappedPromise);
1114
1430
  }
1115
1431
  }
1116
1432
  };
@@ -1136,9 +1452,9 @@ let WrappedResponses$1 = class WrappedResponses extends openai.AzureOpenAI.Respo
1136
1452
  const startTime = Date.now();
1137
1453
  const parentPromise = super.create(openAIParams, options);
1138
1454
  if (openAIParams.stream) {
1139
- return parentPromise.then(value => {
1140
- if ('tee' in value && typeof value.tee === 'function') {
1141
- const [stream1, stream2] = value.tee();
1455
+ const wrappedPromise = parentPromise.then(value => {
1456
+ if (Symbol.asyncIterator in value) {
1457
+ const [stream1, stream2] = monitoredStreamTee(value, (iterator, controller) => new streaming.Stream(iterator, controller));
1142
1458
  (async () => {
1143
1459
  // Hoisted so the catch block can surface the completion ID that
1144
1460
  // was accumulated from the streamed chunks before the failure.
@@ -1172,12 +1488,12 @@ let WrappedResponses$1 = class WrappedResponses extends openai.AzureOpenAI.Respo
1172
1488
  if (chunk.type === 'response.completed' && 'response' in chunk && chunk.response?.output && chunk.response.output.length > 0) {
1173
1489
  finalContent = chunk.response.output;
1174
1490
  }
1175
- if ('usage' in chunk && chunk.usage) {
1491
+ if ('response' in chunk && chunk.response?.usage) {
1176
1492
  usage = {
1177
- inputTokens: chunk.usage.input_tokens ?? 0,
1178
- outputTokens: chunk.usage.output_tokens ?? 0,
1179
- reasoningTokens: chunk.usage.output_tokens_details?.reasoning_tokens ?? 0,
1180
- cacheReadInputTokens: chunk.usage.input_tokens_details?.cached_tokens ?? 0
1493
+ inputTokens: chunk.response.usage.input_tokens ?? 0,
1494
+ outputTokens: chunk.response.usage.output_tokens ?? 0,
1495
+ reasoningTokens: chunk.response.usage.output_tokens_details?.reasoning_tokens ?? 0,
1496
+ cacheReadInputTokens: chunk.response.usage.input_tokens_details?.cached_tokens ?? 0
1181
1497
  };
1182
1498
  }
1183
1499
  }
@@ -1226,6 +1542,7 @@ let WrappedResponses$1 = class WrappedResponses extends openai.AzureOpenAI.Respo
1226
1542
  }
1227
1543
  return value;
1228
1544
  });
1545
+ return preserveProviderPromise(parentPromise, wrappedPromise);
1229
1546
  } else {
1230
1547
  const wrappedPromise = parentPromise.then(async result => {
1231
1548
  if ('output' in result) {
@@ -1273,7 +1590,7 @@ let WrappedResponses$1 = class WrappedResponses extends openai.AzureOpenAI.Respo
1273
1590
  });
1274
1591
  throw error;
1275
1592
  });
1276
- return wrappedPromise;
1593
+ return preserveProviderPromise(parentPromise, wrappedPromise);
1277
1594
  }
1278
1595
  }
1279
1596
  parse(body, options) {
@@ -1282,7 +1599,7 @@ let WrappedResponses$1 = class WrappedResponses extends openai.AzureOpenAI.Respo
1282
1599
  posthogParams
1283
1600
  } = extractPosthogParams(body);
1284
1601
  const startTime = Date.now();
1285
- const parentPromise = super.parse(openAIParams, options);
1602
+ const parentPromise = callWithOriginalCreate(this, super.create.bind(this), () => super.parse(openAIParams, options));
1286
1603
  const wrappedPromise = parentPromise.then(async result => {
1287
1604
  const latency = (Date.now() - startTime) / 1000;
1288
1605
  await captureAiGeneration(this.phClient, {
@@ -1326,7 +1643,7 @@ let WrappedResponses$1 = class WrappedResponses extends openai.AzureOpenAI.Respo
1326
1643
  });
1327
1644
  throw error;
1328
1645
  });
1329
- return wrappedPromise;
1646
+ return preserveProviderPromise(parentPromise, wrappedPromise);
1330
1647
  }
1331
1648
  };
1332
1649
  let WrappedEmbeddings$1 = class WrappedEmbeddings extends openai.AzureOpenAI.Embeddings {
@@ -1381,7 +1698,7 @@ let WrappedEmbeddings$1 = class WrappedEmbeddings extends openai.AzureOpenAI.Emb
1381
1698
  });
1382
1699
  throw error;
1383
1700
  });
1384
- return wrappedPromise;
1701
+ return preserveProviderPromise(parentPromise, wrappedPromise);
1385
1702
  }
1386
1703
  };
1387
1704
 
@@ -1402,25 +1719,6 @@ async function captureAiGenerationAfterSuccess(...args) {
1402
1719
  captureAiGenerationInBackground(...args);
1403
1720
  }
1404
1721
  }
1405
- function preserveAPIPromiseHelpers(parentPromise, wrappedPromise) {
1406
- const apiPromise = wrappedPromise;
1407
- if (typeof parentPromise.asResponse === 'function') {
1408
- apiPromise.asResponse = () => parentPromise.asResponse();
1409
- }
1410
- if (typeof parentPromise.withResponse === 'function') {
1411
- apiPromise.withResponse = async () => {
1412
- const [response, data] = await Promise.all([parentPromise.withResponse(), wrappedPromise]);
1413
- // swaps the `data` payload inside the SDK's generic withResponse shape; the compiler
1414
- // cannot relate the Input- and Output-instantiated conditional types
1415
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
1416
- return {
1417
- ...response,
1418
- data
1419
- };
1420
- };
1421
- }
1422
- return apiPromise;
1423
- }
1424
1722
  const TERMINAL_RESPONSE_STATUSES = new Set(['completed', 'failed', 'cancelled', 'incomplete']);
1425
1723
  function isPendingBackgroundResponse(params, response) {
1426
1724
  return params.background === true && !response.usage && !!response.status && !TERMINAL_RESPONSE_STATUSES.has(response.status);
@@ -1468,8 +1766,8 @@ class WrappedCompletions extends Completions {
1468
1766
  const parentPromise = super.create(openAIParams, options);
1469
1767
  if (openAIParams.stream) {
1470
1768
  const wrappedPromise = parentPromise.then(value => {
1471
- if ('tee' in value) {
1472
- const [stream1, stream2] = value.tee();
1769
+ if (Symbol.asyncIterator in value) {
1770
+ const [stream1, stream2] = monitoredStreamTee(value, (iterator, controller) => new streaming.Stream(iterator, controller));
1473
1771
  (async () => {
1474
1772
  // Hoisted so the catch block can surface whatever was accumulated
1475
1773
  // from the streamed chunks before the failure.
@@ -1667,7 +1965,7 @@ class WrappedCompletions extends Completions {
1667
1965
  }
1668
1966
  return value;
1669
1967
  });
1670
- return preserveAPIPromiseHelpers(parentPromise, wrappedPromise);
1968
+ return preserveProviderPromise(parentPromise, wrappedPromise);
1671
1969
  } else {
1672
1970
  const wrappedPromise = parentPromise.then(async result => {
1673
1971
  if ('choices' in result) {
@@ -1722,7 +2020,7 @@ class WrappedCompletions extends Completions {
1722
2020
  });
1723
2021
  throw error;
1724
2022
  });
1725
- return preserveAPIPromiseHelpers(parentPromise, wrappedPromise);
2023
+ return preserveProviderPromise(parentPromise, wrappedPromise);
1726
2024
  }
1727
2025
  }
1728
2026
  }
@@ -1749,8 +2047,8 @@ class WrappedResponses extends Responses {
1749
2047
  const parentPromise = super.create(openAIParams, options);
1750
2048
  if (openAIParams.stream) {
1751
2049
  const wrappedPromise = parentPromise.then(value => {
1752
- if ('tee' in value && typeof value.tee === 'function') {
1753
- const [stream1, stream2] = value.tee();
2050
+ if (Symbol.asyncIterator in value) {
2051
+ const [stream1, stream2] = monitoredStreamTee(value, (iterator, controller) => new streaming.Stream(iterator, controller));
1754
2052
  (async () => {
1755
2053
  // Hoisted so the catch block can surface the completion ID that
1756
2054
  // was accumulated from the streamed chunks before the failure.
@@ -1860,7 +2158,7 @@ class WrappedResponses extends Responses {
1860
2158
  }
1861
2159
  return value;
1862
2160
  });
1863
- return preserveAPIPromiseHelpers(parentPromise, wrappedPromise);
2161
+ return preserveProviderPromise(parentPromise, wrappedPromise);
1864
2162
  } else {
1865
2163
  const wrappedPromise = parentPromise.then(async result => {
1866
2164
  if ('output' in result) {
@@ -1919,7 +2217,7 @@ class WrappedResponses extends Responses {
1919
2217
  });
1920
2218
  throw error;
1921
2219
  });
1922
- return preserveAPIPromiseHelpers(parentPromise, wrappedPromise);
2220
+ return preserveProviderPromise(parentPromise, wrappedPromise);
1923
2221
  }
1924
2222
  }
1925
2223
  parse(body, options) {
@@ -1928,64 +2226,55 @@ class WrappedResponses extends Responses {
1928
2226
  posthogParams
1929
2227
  } = extractPosthogParams(body);
1930
2228
  const startTime = Date.now();
1931
- const originalCreate = super.create.bind(this);
1932
- const originalSelfRecord = this;
1933
- const tempCreate = originalSelfRecord['create'];
1934
- originalSelfRecord['create'] = originalCreate;
1935
- try {
1936
- const parentPromise = super.parse(openAIParams, options);
1937
- const wrappedPromise = parentPromise.then(async result => {
1938
- if (isPendingBackgroundResponse(openAIParams, result)) {
1939
- return result;
1940
- }
1941
- const latency = (Date.now() - startTime) / 1000;
1942
- await captureAiGeneration(this.phClient, {
1943
- ...posthogParams,
1944
- model: openAIParams.model ?? result.model,
1945
- provider: 'openai',
1946
- input: formatOpenAIResponsesInput(sanitizeOpenAIResponse(openAIParams.input), openAIParams.instructions),
1947
- output: result.output,
1948
- latency,
1949
- baseURL: this.baseURL,
1950
- modelParameters: getModelParams(body, result.service_tier),
1951
- httpStatus: 200,
1952
- usage: {
1953
- inputTokens: result.usage?.input_tokens ?? 0,
1954
- outputTokens: result.usage?.output_tokens ?? 0,
1955
- reasoningTokens: result.usage?.output_tokens_details?.reasoning_tokens ?? 0,
1956
- cacheReadInputTokens: result.usage?.input_tokens_details?.cached_tokens ?? 0,
1957
- rawUsage: result.usage
1958
- },
1959
- stopReason: result.status ?? undefined,
1960
- completionId: result.id,
1961
- providerMetadata: buildProviderMetadata({
1962
- requestId: extractRequestId(result)
1963
- })
1964
- });
2229
+ const parentPromise = callWithOriginalCreate(this, super.create.bind(this), () => super.parse(openAIParams, options));
2230
+ const wrappedPromise = parentPromise.then(async result => {
2231
+ if (isPendingBackgroundResponse(openAIParams, result)) {
1965
2232
  return result;
1966
- }, async error => {
1967
- await captureAiGeneration(this.phClient, {
1968
- ...posthogParams,
1969
- model: openAIParams.model,
1970
- provider: 'openai',
1971
- input: formatOpenAIResponsesInput(sanitizeOpenAIResponse(openAIParams.input), openAIParams.instructions),
1972
- output: [],
1973
- latency: 0,
1974
- baseURL: this.baseURL,
1975
- modelParameters: getModelParams(body),
1976
- usage: {
1977
- inputTokens: 0,
1978
- outputTokens: 0
1979
- },
1980
- error
1981
- });
1982
- throw error;
2233
+ }
2234
+ const latency = (Date.now() - startTime) / 1000;
2235
+ await captureAiGeneration(this.phClient, {
2236
+ ...posthogParams,
2237
+ model: openAIParams.model ?? result.model,
2238
+ provider: 'openai',
2239
+ input: formatOpenAIResponsesInput(sanitizeOpenAIResponse(openAIParams.input), openAIParams.instructions),
2240
+ output: result.output,
2241
+ latency,
2242
+ baseURL: this.baseURL,
2243
+ modelParameters: getModelParams(body, result.service_tier),
2244
+ httpStatus: 200,
2245
+ usage: {
2246
+ inputTokens: result.usage?.input_tokens ?? 0,
2247
+ outputTokens: result.usage?.output_tokens ?? 0,
2248
+ reasoningTokens: result.usage?.output_tokens_details?.reasoning_tokens ?? 0,
2249
+ cacheReadInputTokens: result.usage?.input_tokens_details?.cached_tokens ?? 0,
2250
+ rawUsage: result.usage
2251
+ },
2252
+ stopReason: result.status ?? undefined,
2253
+ completionId: result.id,
2254
+ providerMetadata: buildProviderMetadata({
2255
+ requestId: extractRequestId(result)
2256
+ })
1983
2257
  });
1984
- return preserveAPIPromiseHelpers(parentPromise, wrappedPromise);
1985
- } finally {
1986
- // Restore our wrapped create method
1987
- originalSelfRecord['create'] = tempCreate;
1988
- }
2258
+ return result;
2259
+ }, async error => {
2260
+ await captureAiGeneration(this.phClient, {
2261
+ ...posthogParams,
2262
+ model: openAIParams.model,
2263
+ provider: 'openai',
2264
+ input: formatOpenAIResponsesInput(sanitizeOpenAIResponse(openAIParams.input), openAIParams.instructions),
2265
+ output: [],
2266
+ latency: 0,
2267
+ baseURL: this.baseURL,
2268
+ modelParameters: getModelParams(body),
2269
+ usage: {
2270
+ inputTokens: 0,
2271
+ outputTokens: 0
2272
+ },
2273
+ error
2274
+ });
2275
+ throw error;
2276
+ });
2277
+ return preserveProviderPromise(parentPromise, wrappedPromise);
1989
2278
  }
1990
2279
  }
1991
2280
  class WrappedEmbeddings extends Embeddings {
@@ -2042,7 +2331,7 @@ class WrappedEmbeddings extends Embeddings {
2042
2331
  });
2043
2332
  throw error;
2044
2333
  });
2045
- return preserveAPIPromiseHelpers(parentPromise, wrappedPromise);
2334
+ return preserveProviderPromise(parentPromise, wrappedPromise);
2046
2335
  }
2047
2336
  }
2048
2337
  class WrappedAudio extends Audio {
@@ -2082,8 +2371,8 @@ class WrappedTranscriptions extends Transcriptions {
2082
2371
  const parentPromise = openAIParams.stream ? super.create(openAIParams, options) : super.create(openAIParams, options);
2083
2372
  if (openAIParams.stream) {
2084
2373
  const wrappedPromise = parentPromise.then(value => {
2085
- if ('tee' in value && typeof value.tee === 'function') {
2086
- const [stream1, stream2] = value.tee();
2374
+ if (Symbol.asyncIterator in value) {
2375
+ const [stream1, stream2] = monitoredStreamTee(value, (iterator, controller) => new streaming.Stream(iterator, controller));
2087
2376
  (async () => {
2088
2377
  try {
2089
2378
  let finalContent = '';
@@ -2152,7 +2441,7 @@ class WrappedTranscriptions extends Transcriptions {
2152
2441
  }
2153
2442
  return value;
2154
2443
  });
2155
- return preserveAPIPromiseHelpers(parentPromise, wrappedPromise);
2444
+ return preserveProviderPromise(parentPromise, wrappedPromise);
2156
2445
  } else {
2157
2446
  const wrappedPromise = parentPromise.then(async result => {
2158
2447
  if (result && typeof result === 'object' && 'text' in result) {
@@ -2193,7 +2482,7 @@ class WrappedTranscriptions extends Transcriptions {
2193
2482
  });
2194
2483
  throw error;
2195
2484
  });
2196
- return preserveAPIPromiseHelpers(parentPromise, wrappedPromise);
2485
+ return preserveProviderPromise(parentPromise, wrappedPromise);
2197
2486
  }
2198
2487
  }
2199
2488
  }