@posthog/ai 8.6.3 → 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.
@@ -3,6 +3,7 @@ import { PostHog } from 'posthog-node';
3
3
  import { Stream } from 'openai/streaming';
4
4
  import { ParsedResponse } from 'openai/resources/responses/responses';
5
5
  import { ResponseCreateParamsWithTools, ExtractParsedContentFromParams } from 'openai/lib/ResponsesParser';
6
+ import { AzureClientOptions } from 'openai/azure';
6
7
 
7
8
  interface MonitoringEventPropertiesWithDefaults {
8
9
  distinctId?: string;
@@ -34,10 +35,9 @@ type ResponsesCreateParamsNonStreaming$1 = OpenAIOrignal.Responses.ResponseCreat
34
35
  type ResponsesCreateParamsStreaming$1 = OpenAIOrignal.Responses.ResponseCreateParamsStreaming;
35
36
  type CreateEmbeddingResponse$1 = OpenAIOrignal.CreateEmbeddingResponse;
36
37
  type EmbeddingCreateParams$1 = OpenAIOrignal.EmbeddingCreateParams;
37
- interface MonitoringOpenAIConfig$1 {
38
+ interface MonitoringOpenAIConfig$1 extends AzureClientOptions {
38
39
  apiKey: string;
39
40
  posthog: PostHog;
40
- baseURL?: string;
41
41
  }
42
42
  type RequestOptions$1 = Record<string, any>;
43
43
  declare class PostHogAzureOpenAI extends AzureOpenAI {
@@ -534,7 +534,7 @@ function formatOpenAIResponsesInput(input, instructions) {
534
534
  return messages;
535
535
  }
536
536
 
537
- var version = "8.6.3";
537
+ var version = "8.6.4";
538
538
 
539
539
  const DEFAULT_MAX_DEPTH = 3;
540
540
  const MAX_STACK_LINES = 20;
@@ -667,6 +667,8 @@ const captureAiGeneration$1 = async (client, options) => {
667
667
  if (httpStatus === undefined) {
668
668
  if (typeof options.error === 'object' && 'status' in options.error && typeof options.error.status === 'number') {
669
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;
670
672
  } else {
671
673
  httpStatus = 500;
672
674
  }
@@ -846,6 +848,98 @@ function buildProviderMetadata(fields) {
846
848
  return Object.keys(metadata).length > 0 ? metadata : undefined;
847
849
  }
848
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
+
849
943
  /**
850
944
  * Splits an SDK stream into a monitoring branch and a caller branch without
851
945
  * allowing either branch to read ahead of the other. Unlike the SDKs' `tee()`
@@ -1101,7 +1195,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends AzureOpenAI.Chat.Com
1101
1195
  const startTime = Date.now();
1102
1196
  const parentPromise = super.create(openAIParams, options);
1103
1197
  if (openAIParams.stream) {
1104
- return parentPromise.then(value => {
1198
+ const wrappedPromise = parentPromise.then(value => {
1105
1199
  if (Symbol.asyncIterator in value) {
1106
1200
  const [stream1, stream2] = monitoredStreamTee(value, (iterator, controller) => new Stream(iterator, controller));
1107
1201
  (async () => {
@@ -1279,6 +1373,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends AzureOpenAI.Chat.Com
1279
1373
  }
1280
1374
  return value;
1281
1375
  });
1376
+ return preserveProviderPromise(parentPromise, wrappedPromise);
1282
1377
  } else {
1283
1378
  const wrappedPromise = parentPromise.then(async result => {
1284
1379
  if ('choices' in result) {
@@ -1327,7 +1422,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends AzureOpenAI.Chat.Com
1327
1422
  });
1328
1423
  throw error;
1329
1424
  });
1330
- return wrappedPromise;
1425
+ return preserveProviderPromise(parentPromise, wrappedPromise);
1331
1426
  }
1332
1427
  }
1333
1428
  };
@@ -1353,7 +1448,7 @@ let WrappedResponses$1 = class WrappedResponses extends AzureOpenAI.Responses {
1353
1448
  const startTime = Date.now();
1354
1449
  const parentPromise = super.create(openAIParams, options);
1355
1450
  if (openAIParams.stream) {
1356
- return parentPromise.then(value => {
1451
+ const wrappedPromise = parentPromise.then(value => {
1357
1452
  if (Symbol.asyncIterator in value) {
1358
1453
  const [stream1, stream2] = monitoredStreamTee(value, (iterator, controller) => new Stream(iterator, controller));
1359
1454
  (async () => {
@@ -1443,6 +1538,7 @@ let WrappedResponses$1 = class WrappedResponses extends AzureOpenAI.Responses {
1443
1538
  }
1444
1539
  return value;
1445
1540
  });
1541
+ return preserveProviderPromise(parentPromise, wrappedPromise);
1446
1542
  } else {
1447
1543
  const wrappedPromise = parentPromise.then(async result => {
1448
1544
  if ('output' in result) {
@@ -1490,7 +1586,7 @@ let WrappedResponses$1 = class WrappedResponses extends AzureOpenAI.Responses {
1490
1586
  });
1491
1587
  throw error;
1492
1588
  });
1493
- return wrappedPromise;
1589
+ return preserveProviderPromise(parentPromise, wrappedPromise);
1494
1590
  }
1495
1591
  }
1496
1592
  parse(body, options) {
@@ -1499,7 +1595,7 @@ let WrappedResponses$1 = class WrappedResponses extends AzureOpenAI.Responses {
1499
1595
  posthogParams
1500
1596
  } = extractPosthogParams(body);
1501
1597
  const startTime = Date.now();
1502
- const parentPromise = super.parse(openAIParams, options);
1598
+ const parentPromise = callWithOriginalCreate(this, super.create.bind(this), () => super.parse(openAIParams, options));
1503
1599
  const wrappedPromise = parentPromise.then(async result => {
1504
1600
  const latency = (Date.now() - startTime) / 1000;
1505
1601
  await captureAiGeneration(this.phClient, {
@@ -1543,7 +1639,7 @@ let WrappedResponses$1 = class WrappedResponses extends AzureOpenAI.Responses {
1543
1639
  });
1544
1640
  throw error;
1545
1641
  });
1546
- return wrappedPromise;
1642
+ return preserveProviderPromise(parentPromise, wrappedPromise);
1547
1643
  }
1548
1644
  };
1549
1645
  let WrappedEmbeddings$1 = class WrappedEmbeddings extends AzureOpenAI.Embeddings {
@@ -1598,7 +1694,7 @@ let WrappedEmbeddings$1 = class WrappedEmbeddings extends AzureOpenAI.Embeddings
1598
1694
  });
1599
1695
  throw error;
1600
1696
  });
1601
- return wrappedPromise;
1697
+ return preserveProviderPromise(parentPromise, wrappedPromise);
1602
1698
  }
1603
1699
  };
1604
1700
 
@@ -1619,25 +1715,6 @@ async function captureAiGenerationAfterSuccess(...args) {
1619
1715
  captureAiGenerationInBackground(...args);
1620
1716
  }
1621
1717
  }
1622
- function preserveAPIPromiseHelpers(parentPromise, wrappedPromise) {
1623
- const apiPromise = wrappedPromise;
1624
- if (typeof parentPromise.asResponse === 'function') {
1625
- apiPromise.asResponse = () => parentPromise.asResponse();
1626
- }
1627
- if (typeof parentPromise.withResponse === 'function') {
1628
- apiPromise.withResponse = async () => {
1629
- const [response, data] = await Promise.all([parentPromise.withResponse(), wrappedPromise]);
1630
- // swaps the `data` payload inside the SDK's generic withResponse shape; the compiler
1631
- // cannot relate the Input- and Output-instantiated conditional types
1632
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
1633
- return {
1634
- ...response,
1635
- data
1636
- };
1637
- };
1638
- }
1639
- return apiPromise;
1640
- }
1641
1718
  const TERMINAL_RESPONSE_STATUSES = new Set(['completed', 'failed', 'cancelled', 'incomplete']);
1642
1719
  function isPendingBackgroundResponse(params, response) {
1643
1720
  return params.background === true && !response.usage && !!response.status && !TERMINAL_RESPONSE_STATUSES.has(response.status);
@@ -1884,7 +1961,7 @@ class WrappedCompletions extends Completions {
1884
1961
  }
1885
1962
  return value;
1886
1963
  });
1887
- return preserveAPIPromiseHelpers(parentPromise, wrappedPromise);
1964
+ return preserveProviderPromise(parentPromise, wrappedPromise);
1888
1965
  } else {
1889
1966
  const wrappedPromise = parentPromise.then(async result => {
1890
1967
  if ('choices' in result) {
@@ -1939,7 +2016,7 @@ class WrappedCompletions extends Completions {
1939
2016
  });
1940
2017
  throw error;
1941
2018
  });
1942
- return preserveAPIPromiseHelpers(parentPromise, wrappedPromise);
2019
+ return preserveProviderPromise(parentPromise, wrappedPromise);
1943
2020
  }
1944
2021
  }
1945
2022
  }
@@ -2077,7 +2154,7 @@ class WrappedResponses extends Responses {
2077
2154
  }
2078
2155
  return value;
2079
2156
  });
2080
- return preserveAPIPromiseHelpers(parentPromise, wrappedPromise);
2157
+ return preserveProviderPromise(parentPromise, wrappedPromise);
2081
2158
  } else {
2082
2159
  const wrappedPromise = parentPromise.then(async result => {
2083
2160
  if ('output' in result) {
@@ -2136,7 +2213,7 @@ class WrappedResponses extends Responses {
2136
2213
  });
2137
2214
  throw error;
2138
2215
  });
2139
- return preserveAPIPromiseHelpers(parentPromise, wrappedPromise);
2216
+ return preserveProviderPromise(parentPromise, wrappedPromise);
2140
2217
  }
2141
2218
  }
2142
2219
  parse(body, options) {
@@ -2145,64 +2222,55 @@ class WrappedResponses extends Responses {
2145
2222
  posthogParams
2146
2223
  } = extractPosthogParams(body);
2147
2224
  const startTime = Date.now();
2148
- const originalCreate = super.create.bind(this);
2149
- const originalSelfRecord = this;
2150
- const tempCreate = originalSelfRecord['create'];
2151
- originalSelfRecord['create'] = originalCreate;
2152
- try {
2153
- const parentPromise = super.parse(openAIParams, options);
2154
- const wrappedPromise = parentPromise.then(async result => {
2155
- if (isPendingBackgroundResponse(openAIParams, result)) {
2156
- return result;
2157
- }
2158
- const latency = (Date.now() - startTime) / 1000;
2159
- await captureAiGeneration(this.phClient, {
2160
- ...posthogParams,
2161
- model: openAIParams.model ?? result.model,
2162
- provider: 'openai',
2163
- input: formatOpenAIResponsesInput(sanitizeOpenAIResponse(openAIParams.input), openAIParams.instructions),
2164
- output: result.output,
2165
- latency,
2166
- baseURL: this.baseURL,
2167
- modelParameters: getModelParams(body, result.service_tier),
2168
- httpStatus: 200,
2169
- usage: {
2170
- inputTokens: result.usage?.input_tokens ?? 0,
2171
- outputTokens: result.usage?.output_tokens ?? 0,
2172
- reasoningTokens: result.usage?.output_tokens_details?.reasoning_tokens ?? 0,
2173
- cacheReadInputTokens: result.usage?.input_tokens_details?.cached_tokens ?? 0,
2174
- rawUsage: result.usage
2175
- },
2176
- stopReason: result.status ?? undefined,
2177
- completionId: result.id,
2178
- providerMetadata: buildProviderMetadata({
2179
- requestId: extractRequestId(result)
2180
- })
2181
- });
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)) {
2182
2228
  return result;
2183
- }, async error => {
2184
- await captureAiGeneration(this.phClient, {
2185
- ...posthogParams,
2186
- model: openAIParams.model,
2187
- provider: 'openai',
2188
- input: formatOpenAIResponsesInput(sanitizeOpenAIResponse(openAIParams.input), openAIParams.instructions),
2189
- output: [],
2190
- latency: 0,
2191
- baseURL: this.baseURL,
2192
- modelParameters: getModelParams(body),
2193
- usage: {
2194
- inputTokens: 0,
2195
- outputTokens: 0
2196
- },
2197
- error
2198
- });
2199
- 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
+ })
2200
2253
  });
2201
- return preserveAPIPromiseHelpers(parentPromise, wrappedPromise);
2202
- } finally {
2203
- // Restore our wrapped create method
2204
- originalSelfRecord['create'] = tempCreate;
2205
- }
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);
2206
2274
  }
2207
2275
  }
2208
2276
  class WrappedEmbeddings extends Embeddings {
@@ -2259,7 +2327,7 @@ class WrappedEmbeddings extends Embeddings {
2259
2327
  });
2260
2328
  throw error;
2261
2329
  });
2262
- return preserveAPIPromiseHelpers(parentPromise, wrappedPromise);
2330
+ return preserveProviderPromise(parentPromise, wrappedPromise);
2263
2331
  }
2264
2332
  }
2265
2333
  class WrappedAudio extends Audio {
@@ -2369,7 +2437,7 @@ class WrappedTranscriptions extends Transcriptions {
2369
2437
  }
2370
2438
  return value;
2371
2439
  });
2372
- return preserveAPIPromiseHelpers(parentPromise, wrappedPromise);
2440
+ return preserveProviderPromise(parentPromise, wrappedPromise);
2373
2441
  } else {
2374
2442
  const wrappedPromise = parentPromise.then(async result => {
2375
2443
  if (result && typeof result === 'object' && 'text' in result) {
@@ -2410,7 +2478,7 @@ class WrappedTranscriptions extends Transcriptions {
2410
2478
  });
2411
2479
  throw error;
2412
2480
  });
2413
- return preserveAPIPromiseHelpers(parentPromise, wrappedPromise);
2481
+ return preserveProviderPromise(parentPromise, wrappedPromise);
2414
2482
  }
2415
2483
  }
2416
2484
  }