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