@posthog/ai 7.16.15 → 7.17.1

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.
package/dist/index.cjs CHANGED
@@ -9,28 +9,26 @@ var genai = require('@google/genai');
9
9
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
10
 
11
11
  function _interopNamespace(e) {
12
- if (e && e.__esModule) return e;
13
- var n = Object.create(null);
14
- if (e) {
15
- Object.keys(e).forEach(function (k) {
16
- if (k !== 'default') {
17
- var d = Object.getOwnPropertyDescriptor(e, k);
18
- Object.defineProperty(n, k, d.get ? d : {
19
- enumerable: true,
20
- get: function () { return e[k]; }
12
+ if (e && e.__esModule) return e;
13
+ var n = Object.create(null);
14
+ if (e) {
15
+ Object.keys(e).forEach(function (k) {
16
+ if (k !== 'default') {
17
+ var d = Object.getOwnPropertyDescriptor(e, k);
18
+ Object.defineProperty(n, k, d.get ? d : {
19
+ enumerable: true,
20
+ get: function () { return e[k]; }
21
+ });
22
+ }
21
23
  });
22
- }
23
- });
24
- }
25
- n.default = e;
26
- return Object.freeze(n);
24
+ }
25
+ n.default = e;
26
+ return Object.freeze(n);
27
27
  }
28
28
 
29
29
  var uuid__namespace = /*#__PURE__*/_interopNamespace(uuid);
30
30
  var AnthropicOriginal__default = /*#__PURE__*/_interopDefault(AnthropicOriginal);
31
31
 
32
- var version = "7.16.15";
33
-
34
32
  // Type guards for safer type checking
35
33
  const isString = value => {
36
34
  return typeof value === 'string';
@@ -268,6 +266,13 @@ function getTokensSource(posthogProperties) {
268
266
  // limit large outputs by truncating to 200kb (approx 200k bytes)
269
267
  const MAX_OUTPUT_SIZE = 200000;
270
268
  const STRING_FORMAT = 'utf8';
269
+ // Reused across calls to avoid per-invocation allocation; truncate() runs
270
+ // hundreds of times for prompts with many parts.
271
+ const sharedTextEncoder = new TextEncoder();
272
+ const sharedTextDecoder = new TextDecoder(STRING_FORMAT, {
273
+ fatal: false
274
+ });
275
+ const utf8ByteLength = str => sharedTextEncoder.encode(str).byteLength;
271
276
  /**
272
277
  * Safely converts content to a string, preserving structure for objects/arrays.
273
278
  * - If content is already a string, returns it as-is
@@ -538,19 +543,15 @@ const truncate = input => {
538
543
  return '';
539
544
  }
540
545
  // Check if we need to truncate and ensure STRING_FORMAT is respected
541
- const encoder = new TextEncoder();
542
- const buffer = encoder.encode(str);
546
+ const buffer = sharedTextEncoder.encode(str);
543
547
  if (buffer.length <= MAX_OUTPUT_SIZE) {
544
548
  // Ensure STRING_FORMAT is respected
545
- return new TextDecoder(STRING_FORMAT).decode(buffer);
549
+ return sharedTextDecoder.decode(buffer);
546
550
  }
547
- // Truncate the buffer and ensure a valid string is returned
551
+ // Truncate the buffer and ensure a valid string is returned.
552
+ // fatal: false means we get U+FFFD at the end if truncation broke the encoding.
548
553
  const truncatedBuffer = buffer.slice(0, MAX_OUTPUT_SIZE);
549
- // fatal: false means we get U+FFFD at the end if truncation broke the encoding
550
- const decoder = new TextDecoder(STRING_FORMAT, {
551
- fatal: false
552
- });
553
- let truncatedStr = decoder.decode(truncatedBuffer);
554
+ let truncatedStr = sharedTextDecoder.decode(truncatedBuffer);
554
555
  if (truncatedStr.endsWith('\uFFFD')) {
555
556
  truncatedStr = truncatedStr.slice(0, -1);
556
557
  }
@@ -679,11 +680,11 @@ const extractAvailableToolCalls = (provider, params) => {
679
680
  }
680
681
  return null;
681
682
  };
682
- var AIEvent;
683
+ exports.AIEvent = void 0;
683
684
  (function (AIEvent) {
684
685
  AIEvent["Generation"] = "$ai_generation";
685
686
  AIEvent["Embedding"] = "$ai_embedding";
686
- })(AIEvent || (AIEvent = {}));
687
+ })(exports.AIEvent || (exports.AIEvent = {}));
687
688
  function sanitizeValues(obj) {
688
689
  if (obj === undefined || obj === null) {
689
690
  return obj;
@@ -734,73 +735,107 @@ function addDefaults(params) {
734
735
  traceId: params.traceId ?? uuid.v4()
735
736
  };
736
737
  }
737
- const sendEventWithErrorToPosthog = async ({
738
- client,
739
- traceId,
740
- error,
741
- ...args
742
- }) => {
743
- const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
744
- const properties = {
745
- client,
746
- traceId,
747
- httpStatus,
748
- error: JSON.stringify(error),
749
- ...args
750
- };
751
- const enrichedError = error;
752
- if (client.options?.enableExceptionAutocapture) {
753
- // assign a uuid that can be used to link the trace and exception events
754
- const exceptionId = core.uuidv7();
755
- client.captureException(error, undefined, {
756
- $ai_trace_id: traceId
757
- }, exceptionId);
758
- enrichedError.__posthog_previously_captured_error = true;
759
- properties.exceptionId = exceptionId;
760
- }
761
- await sendEventToPosthog(properties);
762
- return enrichedError;
763
- };
764
- const sendEventToPosthog = async ({
765
- client,
766
- eventType = AIEvent.Generation,
767
- distinctId,
768
- traceId,
769
- model,
770
- provider,
771
- input,
772
- output,
773
- latency,
774
- timeToFirstToken,
775
- baseURL,
776
- params,
777
- httpStatus = 200,
778
- usage = {},
779
- error,
780
- exceptionId,
781
- stopReason,
782
- tools,
783
- captureImmediate = false
784
- }) => {
785
- if (!client.capture) {
786
- return Promise.resolve();
738
+ function formatOpenAIResponsesInput(input, instructions) {
739
+ const messages = [];
740
+ if (instructions) {
741
+ messages.push({
742
+ role: 'system',
743
+ content: instructions
744
+ });
745
+ }
746
+ if (Array.isArray(input)) {
747
+ for (const item of input) {
748
+ if (typeof item === 'string') {
749
+ messages.push({
750
+ role: 'user',
751
+ content: item
752
+ });
753
+ } else if (item && typeof item === 'object') {
754
+ const obj = item;
755
+ const role = isString(obj.role) ? obj.role : 'user';
756
+ // Handle content properly - preserve structure for objects/arrays
757
+ const content = obj.content ?? obj.text ?? item;
758
+ messages.push({
759
+ role,
760
+ content: toContentString(content)
761
+ });
762
+ } else {
763
+ messages.push({
764
+ role: 'user',
765
+ content: toContentString(item)
766
+ });
767
+ }
768
+ }
769
+ } else if (typeof input === 'string') {
770
+ messages.push({
771
+ role: 'user',
772
+ content: input
773
+ });
774
+ } else if (input) {
775
+ messages.push({
776
+ role: 'user',
777
+ content: toContentString(input)
778
+ });
787
779
  }
788
- // sanitize input and output for UTF-8 validity
789
- const safeInput = sanitizeValues(input);
790
- const safeOutput = sanitizeValues(output);
791
- const safeError = sanitizeValues(error);
780
+ return messages;
781
+ }
782
+
783
+ var version = "7.17.1";
784
+
785
+ /**
786
+ * Capture an `$ai_generation` (or `$ai_embedding`) event to PostHog.
787
+ *
788
+ * This is the canonical primitive that every `@posthog/ai` wrapper
789
+ * (`withTracing`, `OpenAI`, `Anthropic`, `GoogleGenAI`, …) funnels through, so
790
+ * external code can use it directly to instrument LLM calls made through
791
+ * arbitrary clients (Cloudflare Workers AI, custom HTTP, etc.) and get the
792
+ * same events the SDK wrappers produce.
793
+ *
794
+ * When `error` is set, the event is captured as an error. If the error is an
795
+ * object, it is mutated in place to set `__posthog_previously_captured_error`
796
+ * so callers can re-throw the original error reference safely.
797
+ */
798
+ const captureAiGeneration = async (client, options) => {
799
+ if (!client.capture) {
800
+ return;
801
+ }
802
+ const traceId = options.traceId ?? uuid.v4();
803
+ const eventType = options.eventType ?? exports.AIEvent.Generation;
804
+ const privacyMode = options.privacyMode ?? false;
805
+ const usage = options.usage ?? {};
806
+ const safeInput = sanitizeValues(options.input);
807
+ const safeOutput = sanitizeValues(options.output);
808
+ let httpStatus = options.httpStatus;
792
809
  let errorData = {};
793
- if (error) {
810
+ if (options.error) {
811
+ if (httpStatus === undefined) {
812
+ if (typeof options.error === 'object' && 'status' in options.error && typeof options.error.status === 'number') {
813
+ httpStatus = options.error.status;
814
+ } else {
815
+ httpStatus = 500;
816
+ }
817
+ }
818
+ let exceptionId;
819
+ if (client.options?.enableExceptionAutocapture) {
820
+ exceptionId = core.uuidv7();
821
+ client.captureException(options.error, undefined, {
822
+ $ai_trace_id: traceId
823
+ }, exceptionId);
824
+ if (typeof options.error === 'object') {
825
+ options.error.__posthog_previously_captured_error = true;
826
+ }
827
+ }
794
828
  errorData = {
795
829
  $ai_is_error: true,
796
- $ai_error: safeError,
830
+ $ai_error: sanitizeValues(JSON.stringify(options.error)),
797
831
  $exception_event_id: exceptionId
798
832
  };
799
833
  }
834
+ httpStatus = httpStatus ?? 200;
800
835
  let costOverrideData = {};
801
- if (params.posthogCostOverride) {
802
- const inputCostUSD = (params.posthogCostOverride.inputCost ?? 0) * (usage.inputTokens ?? 0);
803
- const outputCostUSD = (params.posthogCostOverride.outputCost ?? 0) * (usage.outputTokens ?? 0);
836
+ if (options.costOverride) {
837
+ const inputCostUSD = (options.costOverride.inputCost ?? 0) * (usage.inputTokens ?? 0);
838
+ const outputCostUSD = (options.costOverride.outputCost ?? 0) * (usage.outputTokens ?? 0);
804
839
  costOverrideData = {
805
840
  $ai_input_cost_usd: inputCostUSD,
806
841
  $ai_output_cost_usd: outputCostUSD,
@@ -827,95 +862,49 @@ const sendEventToPosthog = async ({
827
862
  const properties = {
828
863
  $ai_lib: 'posthog-ai',
829
864
  $ai_lib_version: version,
830
- $ai_provider: params.posthogProviderOverride ?? provider,
831
- $ai_model: params.posthogModelOverride ?? model,
832
- $ai_model_parameters: getModelParams(params),
833
- $ai_input: withPrivacyMode(client, params.posthogPrivacyMode ?? false, safeInput),
834
- $ai_output_choices: withPrivacyMode(client, params.posthogPrivacyMode ?? false, safeOutput),
865
+ $ai_provider: options.providerOverride ?? options.provider,
866
+ $ai_model: options.modelOverride ?? options.model,
867
+ $ai_model_parameters: options.modelParameters ?? {},
868
+ $ai_input: withPrivacyMode(client, privacyMode, safeInput),
869
+ $ai_output_choices: withPrivacyMode(client, privacyMode, safeOutput),
835
870
  $ai_http_status: httpStatus,
836
871
  $ai_input_tokens: usage.inputTokens ?? 0,
837
872
  ...(usage.outputTokens !== undefined ? {
838
873
  $ai_output_tokens: usage.outputTokens
839
874
  } : {}),
840
875
  ...additionalTokenValues,
841
- $ai_latency: latency,
842
- ...(timeToFirstToken !== undefined ? {
843
- $ai_time_to_first_token: timeToFirstToken
876
+ $ai_latency: options.latency ?? 0,
877
+ ...(options.timeToFirstToken !== undefined ? {
878
+ $ai_time_to_first_token: options.timeToFirstToken
844
879
  } : {}),
845
880
  $ai_trace_id: traceId,
846
- $ai_base_url: baseURL,
847
- ...params.posthogProperties,
848
- $ai_tokens_source: getTokensSource(params.posthogProperties),
849
- ...(distinctId ? {} : {
881
+ $ai_base_url: options.baseURL ?? '',
882
+ ...options.properties,
883
+ $ai_tokens_source: getTokensSource(options.properties),
884
+ ...(options.distinctId ? {} : {
850
885
  $process_person_profile: false
851
886
  }),
852
- ...(stopReason ? {
853
- $ai_stop_reason: stopReason
887
+ ...(options.stopReason ? {
888
+ $ai_stop_reason: options.stopReason
854
889
  } : {}),
855
- ...(tools ? {
856
- $ai_tools: tools
890
+ ...(options.tools ? {
891
+ $ai_tools: options.tools
857
892
  } : {}),
858
893
  ...errorData,
859
894
  ...costOverrideData
860
895
  };
861
896
  const event = {
862
- distinctId: distinctId ?? traceId,
897
+ distinctId: options.distinctId ?? traceId,
863
898
  event: eventType,
864
899
  properties,
865
- groups: params.posthogGroups
900
+ groups: options.groups
866
901
  };
867
- if (captureImmediate) {
868
- // await capture promise to send single event in serverless environments
902
+ if (options.captureImmediate) {
869
903
  await client.captureImmediate(event);
870
904
  } else {
871
905
  client.capture(event);
872
906
  }
873
- return Promise.resolve();
874
907
  };
875
- function formatOpenAIResponsesInput(input, instructions) {
876
- const messages = [];
877
- if (instructions) {
878
- messages.push({
879
- role: 'system',
880
- content: instructions
881
- });
882
- }
883
- if (Array.isArray(input)) {
884
- for (const item of input) {
885
- if (typeof item === 'string') {
886
- messages.push({
887
- role: 'user',
888
- content: item
889
- });
890
- } else if (item && typeof item === 'object') {
891
- const obj = item;
892
- const role = isString(obj.role) ? obj.role : 'user';
893
- // Handle content properly - preserve structure for objects/arrays
894
- const content = obj.content ?? obj.text ?? item;
895
- messages.push({
896
- role,
897
- content: toContentString(content)
898
- });
899
- } else {
900
- messages.push({
901
- role: 'user',
902
- content: toContentString(item)
903
- });
904
- }
905
- }
906
- } else if (typeof input === 'string') {
907
- messages.push({
908
- role: 'user',
909
- content: input
910
- });
911
- } else if (input) {
912
- messages.push({
913
- role: 'user',
914
- content: toContentString(input)
915
- });
916
- }
917
- return messages;
918
- }
919
908
 
920
909
  /**
921
910
  * Checks if a ResponseStreamEvent chunk represents the first token/content from the model.
@@ -1084,8 +1073,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
1084
1073
  const latency = (Date.now() - startTime) / 1000;
1085
1074
  const timeToFirstToken = firstTokenTime !== undefined ? (firstTokenTime - startTime) / 1000 : undefined;
1086
1075
  const availableTools = extractAvailableToolCalls('openai', openAIParams);
1087
- await sendEventToPosthog({
1088
- client: this.phClient,
1076
+ await captureAiGeneration(this.phClient, {
1089
1077
  ...posthogParams,
1090
1078
  model: openAIParams.model ?? modelFromResponse,
1091
1079
  provider: 'openai',
@@ -1094,7 +1082,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
1094
1082
  latency,
1095
1083
  timeToFirstToken,
1096
1084
  baseURL: this.baseURL,
1097
- params: body,
1085
+ modelParameters: getModelParams(body),
1098
1086
  httpStatus: 200,
1099
1087
  usage: {
1100
1088
  inputTokens: usage.inputTokens,
@@ -1108,8 +1096,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
1108
1096
  tools: availableTools
1109
1097
  });
1110
1098
  } catch (error) {
1111
- const enrichedError = await sendEventWithErrorToPosthog({
1112
- client: this.phClient,
1099
+ await captureAiGeneration(this.phClient, {
1113
1100
  ...posthogParams,
1114
1101
  model: openAIParams.model,
1115
1102
  provider: 'openai',
@@ -1117,14 +1104,14 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
1117
1104
  output: [],
1118
1105
  latency: 0,
1119
1106
  baseURL: this.baseURL,
1120
- params: body,
1107
+ modelParameters: getModelParams(body),
1121
1108
  usage: {
1122
1109
  inputTokens: 0,
1123
1110
  outputTokens: 0
1124
1111
  },
1125
1112
  error
1126
1113
  });
1127
- throw enrichedError;
1114
+ throw error;
1128
1115
  }
1129
1116
  })();
1130
1117
  // Return the other stream to the user
@@ -1138,8 +1125,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
1138
1125
  const latency = (Date.now() - startTime) / 1000;
1139
1126
  const availableTools = extractAvailableToolCalls('openai', openAIParams);
1140
1127
  const formattedOutput = formatResponseOpenAI(result);
1141
- await sendEventToPosthog({
1142
- client: this.phClient,
1128
+ await captureAiGeneration(this.phClient, {
1143
1129
  ...posthogParams,
1144
1130
  model: openAIParams.model ?? result.model,
1145
1131
  provider: 'openai',
@@ -1147,7 +1133,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
1147
1133
  output: formattedOutput,
1148
1134
  latency,
1149
1135
  baseURL: this.baseURL,
1150
- params: body,
1136
+ modelParameters: getModelParams(body),
1151
1137
  httpStatus: 200,
1152
1138
  usage: {
1153
1139
  inputTokens: result.usage?.prompt_tokens ?? 0,
@@ -1164,8 +1150,7 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
1164
1150
  return result;
1165
1151
  }, async error => {
1166
1152
  const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
1167
- await sendEventToPosthog({
1168
- client: this.phClient,
1153
+ await captureAiGeneration(this.phClient, {
1169
1154
  ...posthogParams,
1170
1155
  model: openAIParams.model,
1171
1156
  provider: 'openai',
@@ -1173,13 +1158,13 @@ let WrappedCompletions$1 = class WrappedCompletions extends Completions {
1173
1158
  output: [],
1174
1159
  latency: 0,
1175
1160
  baseURL: this.baseURL,
1176
- params: body,
1161
+ modelParameters: getModelParams(body),
1177
1162
  httpStatus,
1178
1163
  usage: {
1179
1164
  inputTokens: 0,
1180
1165
  outputTokens: 0
1181
1166
  },
1182
- error: JSON.stringify(error)
1167
+ error
1183
1168
  });
1184
1169
  throw error;
1185
1170
  });
@@ -1252,8 +1237,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1252
1237
  const latency = (Date.now() - startTime) / 1000;
1253
1238
  const timeToFirstToken = firstTokenTime !== undefined ? (firstTokenTime - startTime) / 1000 : undefined;
1254
1239
  const availableTools = extractAvailableToolCalls('openai', openAIParams);
1255
- await sendEventToPosthog({
1256
- client: this.phClient,
1240
+ await captureAiGeneration(this.phClient, {
1257
1241
  ...posthogParams,
1258
1242
  model: openAIParams.model ?? modelFromResponse,
1259
1243
  provider: 'openai',
@@ -1262,7 +1246,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1262
1246
  latency,
1263
1247
  timeToFirstToken,
1264
1248
  baseURL: this.baseURL,
1265
- params: body,
1249
+ modelParameters: getModelParams(body),
1266
1250
  httpStatus: 200,
1267
1251
  usage: {
1268
1252
  inputTokens: usage.inputTokens,
@@ -1276,8 +1260,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1276
1260
  tools: availableTools
1277
1261
  });
1278
1262
  } catch (error) {
1279
- const enrichedError = await sendEventWithErrorToPosthog({
1280
- client: this.phClient,
1263
+ await captureAiGeneration(this.phClient, {
1281
1264
  ...posthogParams,
1282
1265
  model: openAIParams.model,
1283
1266
  provider: 'openai',
@@ -1285,14 +1268,14 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1285
1268
  output: [],
1286
1269
  latency: 0,
1287
1270
  baseURL: this.baseURL,
1288
- params: body,
1271
+ modelParameters: getModelParams(body),
1289
1272
  usage: {
1290
1273
  inputTokens: 0,
1291
1274
  outputTokens: 0
1292
1275
  },
1293
- error: error
1276
+ error
1294
1277
  });
1295
- throw enrichedError;
1278
+ throw error;
1296
1279
  }
1297
1280
  })();
1298
1281
  return stream2;
@@ -1307,8 +1290,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1307
1290
  const formattedOutput = formatResponseOpenAI({
1308
1291
  output: result.output
1309
1292
  });
1310
- await sendEventToPosthog({
1311
- client: this.phClient,
1293
+ await captureAiGeneration(this.phClient, {
1312
1294
  ...posthogParams,
1313
1295
  model: openAIParams.model ?? result.model,
1314
1296
  provider: 'openai',
@@ -1316,7 +1298,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1316
1298
  output: formattedOutput,
1317
1299
  latency,
1318
1300
  baseURL: this.baseURL,
1319
- params: body,
1301
+ modelParameters: getModelParams(body),
1320
1302
  httpStatus: 200,
1321
1303
  usage: {
1322
1304
  inputTokens: result.usage?.input_tokens ?? 0,
@@ -1333,8 +1315,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1333
1315
  return result;
1334
1316
  }, async error => {
1335
1317
  const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
1336
- await sendEventToPosthog({
1337
- client: this.phClient,
1318
+ await captureAiGeneration(this.phClient, {
1338
1319
  ...posthogParams,
1339
1320
  model: openAIParams.model,
1340
1321
  provider: 'openai',
@@ -1342,13 +1323,13 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1342
1323
  output: [],
1343
1324
  latency: 0,
1344
1325
  baseURL: this.baseURL,
1345
- params: body,
1326
+ modelParameters: getModelParams(body),
1346
1327
  httpStatus,
1347
1328
  usage: {
1348
1329
  inputTokens: 0,
1349
1330
  outputTokens: 0
1350
1331
  },
1351
- error: JSON.stringify(error)
1332
+ error
1352
1333
  });
1353
1334
  throw error;
1354
1335
  });
@@ -1369,8 +1350,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1369
1350
  const parentPromise = super.parse(openAIParams, options);
1370
1351
  const wrappedPromise = parentPromise.then(async result => {
1371
1352
  const latency = (Date.now() - startTime) / 1000;
1372
- await sendEventToPosthog({
1373
- client: this.phClient,
1353
+ await captureAiGeneration(this.phClient, {
1374
1354
  ...posthogParams,
1375
1355
  model: openAIParams.model ?? result.model,
1376
1356
  provider: 'openai',
@@ -1378,7 +1358,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1378
1358
  output: result.output,
1379
1359
  latency,
1380
1360
  baseURL: this.baseURL,
1381
- params: body,
1361
+ modelParameters: getModelParams(body),
1382
1362
  httpStatus: 200,
1383
1363
  usage: {
1384
1364
  inputTokens: result.usage?.input_tokens ?? 0,
@@ -1391,8 +1371,7 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1391
1371
  });
1392
1372
  return result;
1393
1373
  }, async error => {
1394
- const enrichedError = await sendEventWithErrorToPosthog({
1395
- client: this.phClient,
1374
+ await captureAiGeneration(this.phClient, {
1396
1375
  ...posthogParams,
1397
1376
  model: openAIParams.model,
1398
1377
  provider: 'openai',
@@ -1400,14 +1379,14 @@ let WrappedResponses$1 = class WrappedResponses extends Responses {
1400
1379
  output: [],
1401
1380
  latency: 0,
1402
1381
  baseURL: this.baseURL,
1403
- params: body,
1382
+ modelParameters: getModelParams(body),
1404
1383
  usage: {
1405
1384
  inputTokens: 0,
1406
1385
  outputTokens: 0
1407
1386
  },
1408
- error: JSON.stringify(error)
1387
+ error
1409
1388
  });
1410
- throw enrichedError;
1389
+ throw error;
1411
1390
  });
1412
1391
  return wrappedPromise;
1413
1392
  } finally {
@@ -1431,10 +1410,9 @@ let WrappedEmbeddings$1 = class WrappedEmbeddings extends Embeddings {
1431
1410
  const parentPromise = super.create(openAIParams, options);
1432
1411
  const wrappedPromise = parentPromise.then(async result => {
1433
1412
  const latency = (Date.now() - startTime) / 1000;
1434
- await sendEventToPosthog({
1435
- client: this.phClient,
1413
+ await captureAiGeneration(this.phClient, {
1436
1414
  ...posthogParams,
1437
- eventType: AIEvent.Embedding,
1415
+ eventType: exports.AIEvent.Embedding,
1438
1416
  model: openAIParams.model,
1439
1417
  provider: 'openai',
1440
1418
  input: withPrivacyMode(this.phClient, posthogParams.privacyMode, openAIParams.input),
@@ -1442,7 +1420,7 @@ let WrappedEmbeddings$1 = class WrappedEmbeddings extends Embeddings {
1442
1420
  // Embeddings don't have output content
1443
1421
  latency,
1444
1422
  baseURL: this.baseURL,
1445
- params: body,
1423
+ modelParameters: getModelParams(body),
1446
1424
  httpStatus: 200,
1447
1425
  usage: {
1448
1426
  inputTokens: result.usage?.prompt_tokens ?? 0,
@@ -1452,9 +1430,8 @@ let WrappedEmbeddings$1 = class WrappedEmbeddings extends Embeddings {
1452
1430
  return result;
1453
1431
  }, async error => {
1454
1432
  const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
1455
- await sendEventToPosthog({
1456
- client: this.phClient,
1457
- eventType: AIEvent.Embedding,
1433
+ await captureAiGeneration(this.phClient, {
1434
+ eventType: exports.AIEvent.Embedding,
1458
1435
  ...posthogParams,
1459
1436
  model: openAIParams.model,
1460
1437
  provider: 'openai',
@@ -1463,12 +1440,12 @@ let WrappedEmbeddings$1 = class WrappedEmbeddings extends Embeddings {
1463
1440
  // Embeddings don't have output content
1464
1441
  latency: 0,
1465
1442
  baseURL: this.baseURL,
1466
- params: body,
1443
+ modelParameters: getModelParams(body),
1467
1444
  httpStatus,
1468
1445
  usage: {
1469
1446
  inputTokens: 0
1470
1447
  },
1471
- error: JSON.stringify(error)
1448
+ error
1472
1449
  });
1473
1450
  throw error;
1474
1451
  });
@@ -1527,8 +1504,7 @@ class WrappedTranscriptions extends Transcriptions {
1527
1504
  const latency = (Date.now() - startTime) / 1000;
1528
1505
  const timeToFirstToken = firstTokenTime !== undefined ? (firstTokenTime - startTime) / 1000 : undefined;
1529
1506
  const availableTools = extractAvailableToolCalls('openai', openAIParams);
1530
- await sendEventToPosthog({
1531
- client: this.phClient,
1507
+ await captureAiGeneration(this.phClient, {
1532
1508
  ...posthogParams,
1533
1509
  model: openAIParams.model,
1534
1510
  provider: 'openai',
@@ -1537,14 +1513,13 @@ class WrappedTranscriptions extends Transcriptions {
1537
1513
  latency,
1538
1514
  timeToFirstToken,
1539
1515
  baseURL: this.baseURL,
1540
- params: body,
1516
+ modelParameters: getModelParams(body),
1541
1517
  httpStatus: 200,
1542
1518
  usage,
1543
1519
  tools: availableTools
1544
1520
  });
1545
1521
  } catch (error) {
1546
- const enrichedError = await sendEventWithErrorToPosthog({
1547
- client: this.phClient,
1522
+ await captureAiGeneration(this.phClient, {
1548
1523
  ...posthogParams,
1549
1524
  model: openAIParams.model,
1550
1525
  provider: 'openai',
@@ -1552,14 +1527,14 @@ class WrappedTranscriptions extends Transcriptions {
1552
1527
  output: [],
1553
1528
  latency: 0,
1554
1529
  baseURL: this.baseURL,
1555
- params: body,
1530
+ modelParameters: getModelParams(body),
1556
1531
  usage: {
1557
1532
  inputTokens: 0,
1558
1533
  outputTokens: 0
1559
1534
  },
1560
- error: error
1535
+ error
1561
1536
  });
1562
- throw enrichedError;
1537
+ throw error;
1563
1538
  }
1564
1539
  })();
1565
1540
  return stream2;
@@ -1570,8 +1545,7 @@ class WrappedTranscriptions extends Transcriptions {
1570
1545
  const wrappedPromise = parentPromise.then(async result => {
1571
1546
  if ('text' in result) {
1572
1547
  const latency = (Date.now() - startTime) / 1000;
1573
- await sendEventToPosthog({
1574
- client: this.phClient,
1548
+ await captureAiGeneration(this.phClient, {
1575
1549
  ...posthogParams,
1576
1550
  model: openAIParams.model,
1577
1551
  provider: 'openai',
@@ -1579,7 +1553,7 @@ class WrappedTranscriptions extends Transcriptions {
1579
1553
  output: result.text,
1580
1554
  latency,
1581
1555
  baseURL: this.baseURL,
1582
- params: body,
1556
+ modelParameters: getModelParams(body),
1583
1557
  httpStatus: 200,
1584
1558
  usage: {
1585
1559
  inputTokens: result.usage?.type === 'tokens' ? result.usage.input_tokens ?? 0 : 0,
@@ -1590,8 +1564,7 @@ class WrappedTranscriptions extends Transcriptions {
1590
1564
  return result;
1591
1565
  }
1592
1566
  }, async error => {
1593
- const enrichedError = await sendEventWithErrorToPosthog({
1594
- client: this.phClient,
1567
+ await captureAiGeneration(this.phClient, {
1595
1568
  ...posthogParams,
1596
1569
  model: openAIParams.model,
1597
1570
  provider: 'openai',
@@ -1599,14 +1572,14 @@ class WrappedTranscriptions extends Transcriptions {
1599
1572
  output: [],
1600
1573
  latency: 0,
1601
1574
  baseURL: this.baseURL,
1602
- params: body,
1575
+ modelParameters: getModelParams(body),
1603
1576
  usage: {
1604
1577
  inputTokens: 0,
1605
1578
  outputTokens: 0
1606
1579
  },
1607
- error: error
1580
+ error
1608
1581
  });
1609
- throw enrichedError;
1582
+ throw error;
1610
1583
  });
1611
1584
  return wrappedPromise;
1612
1585
  }
@@ -1751,8 +1724,7 @@ class WrappedCompletions extends openai.AzureOpenAI.Chat.Completions {
1751
1724
  }];
1752
1725
  const latency = (Date.now() - startTime) / 1000;
1753
1726
  const timeToFirstToken = firstTokenTime !== undefined ? (firstTokenTime - startTime) / 1000 : undefined;
1754
- await sendEventToPosthog({
1755
- client: this.phClient,
1727
+ await captureAiGeneration(this.phClient, {
1756
1728
  ...posthogParams,
1757
1729
  model: openAIParams.model ?? modelFromResponse,
1758
1730
  provider: 'azure',
@@ -1761,13 +1733,12 @@ class WrappedCompletions extends openai.AzureOpenAI.Chat.Completions {
1761
1733
  latency,
1762
1734
  timeToFirstToken,
1763
1735
  baseURL: this.baseURL,
1764
- params: body,
1736
+ modelParameters: getModelParams(body),
1765
1737
  httpStatus: 200,
1766
1738
  usage
1767
1739
  });
1768
1740
  } catch (error) {
1769
- const enrichedError = await sendEventWithErrorToPosthog({
1770
- client: this.phClient,
1741
+ await captureAiGeneration(this.phClient, {
1771
1742
  ...posthogParams,
1772
1743
  model: openAIParams.model,
1773
1744
  provider: 'azure',
@@ -1775,14 +1746,14 @@ class WrappedCompletions extends openai.AzureOpenAI.Chat.Completions {
1775
1746
  output: [],
1776
1747
  latency: 0,
1777
1748
  baseURL: this.baseURL,
1778
- params: body,
1749
+ modelParameters: getModelParams(body),
1779
1750
  usage: {
1780
1751
  inputTokens: 0,
1781
1752
  outputTokens: 0
1782
1753
  },
1783
1754
  error: error
1784
1755
  });
1785
- throw enrichedError;
1756
+ throw error;
1786
1757
  }
1787
1758
  })();
1788
1759
  // Return the other stream to the user
@@ -1794,8 +1765,7 @@ class WrappedCompletions extends openai.AzureOpenAI.Chat.Completions {
1794
1765
  const wrappedPromise = parentPromise.then(async result => {
1795
1766
  if ('choices' in result) {
1796
1767
  const latency = (Date.now() - startTime) / 1000;
1797
- await sendEventToPosthog({
1798
- client: this.phClient,
1768
+ await captureAiGeneration(this.phClient, {
1799
1769
  ...posthogParams,
1800
1770
  model: openAIParams.model ?? result.model,
1801
1771
  provider: 'azure',
@@ -1803,7 +1773,7 @@ class WrappedCompletions extends openai.AzureOpenAI.Chat.Completions {
1803
1773
  output: formatResponseOpenAI(result),
1804
1774
  latency,
1805
1775
  baseURL: this.baseURL,
1806
- params: body,
1776
+ modelParameters: getModelParams(body),
1807
1777
  httpStatus: 200,
1808
1778
  usage: {
1809
1779
  inputTokens: result.usage?.prompt_tokens ?? 0,
@@ -1816,8 +1786,7 @@ class WrappedCompletions extends openai.AzureOpenAI.Chat.Completions {
1816
1786
  return result;
1817
1787
  }, async error => {
1818
1788
  const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
1819
- await sendEventToPosthog({
1820
- client: this.phClient,
1789
+ await captureAiGeneration(this.phClient, {
1821
1790
  ...posthogParams,
1822
1791
  model: openAIParams.model,
1823
1792
  provider: 'azure',
@@ -1825,13 +1794,13 @@ class WrappedCompletions extends openai.AzureOpenAI.Chat.Completions {
1825
1794
  output: [],
1826
1795
  latency: 0,
1827
1796
  baseURL: this.baseURL,
1828
- params: body,
1797
+ modelParameters: getModelParams(body),
1829
1798
  httpStatus,
1830
1799
  usage: {
1831
1800
  inputTokens: 0,
1832
1801
  outputTokens: 0
1833
1802
  },
1834
- error: JSON.stringify(error)
1803
+ error
1835
1804
  });
1836
1805
  throw error;
1837
1806
  });
@@ -1891,8 +1860,7 @@ class WrappedResponses extends openai.AzureOpenAI.Responses {
1891
1860
  }
1892
1861
  const latency = (Date.now() - startTime) / 1000;
1893
1862
  const timeToFirstToken = firstTokenTime !== undefined ? (firstTokenTime - startTime) / 1000 : undefined;
1894
- await sendEventToPosthog({
1895
- client: this.phClient,
1863
+ await captureAiGeneration(this.phClient, {
1896
1864
  ...posthogParams,
1897
1865
  model: openAIParams.model ?? modelFromResponse,
1898
1866
  provider: 'azure',
@@ -1901,13 +1869,12 @@ class WrappedResponses extends openai.AzureOpenAI.Responses {
1901
1869
  latency,
1902
1870
  timeToFirstToken,
1903
1871
  baseURL: this.baseURL,
1904
- params: body,
1872
+ modelParameters: getModelParams(body),
1905
1873
  httpStatus: 200,
1906
1874
  usage
1907
1875
  });
1908
1876
  } catch (error) {
1909
- const enrichedError = await sendEventWithErrorToPosthog({
1910
- client: this.phClient,
1877
+ await captureAiGeneration(this.phClient, {
1911
1878
  ...posthogParams,
1912
1879
  model: openAIParams.model,
1913
1880
  provider: 'azure',
@@ -1915,14 +1882,14 @@ class WrappedResponses extends openai.AzureOpenAI.Responses {
1915
1882
  output: [],
1916
1883
  latency: 0,
1917
1884
  baseURL: this.baseURL,
1918
- params: body,
1885
+ modelParameters: getModelParams(body),
1919
1886
  usage: {
1920
1887
  inputTokens: 0,
1921
1888
  outputTokens: 0
1922
1889
  },
1923
1890
  error: error
1924
1891
  });
1925
- throw enrichedError;
1892
+ throw error;
1926
1893
  }
1927
1894
  })();
1928
1895
  return stream2;
@@ -1933,8 +1900,7 @@ class WrappedResponses extends openai.AzureOpenAI.Responses {
1933
1900
  const wrappedPromise = parentPromise.then(async result => {
1934
1901
  if ('output' in result) {
1935
1902
  const latency = (Date.now() - startTime) / 1000;
1936
- await sendEventToPosthog({
1937
- client: this.phClient,
1903
+ await captureAiGeneration(this.phClient, {
1938
1904
  ...posthogParams,
1939
1905
  model: openAIParams.model ?? result.model,
1940
1906
  provider: 'azure',
@@ -1942,7 +1908,7 @@ class WrappedResponses extends openai.AzureOpenAI.Responses {
1942
1908
  output: result.output,
1943
1909
  latency,
1944
1910
  baseURL: this.baseURL,
1945
- params: body,
1911
+ modelParameters: getModelParams(body),
1946
1912
  httpStatus: 200,
1947
1913
  usage: {
1948
1914
  inputTokens: result.usage?.input_tokens ?? 0,
@@ -1955,8 +1921,7 @@ class WrappedResponses extends openai.AzureOpenAI.Responses {
1955
1921
  return result;
1956
1922
  }, async error => {
1957
1923
  const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
1958
- await sendEventToPosthog({
1959
- client: this.phClient,
1924
+ await captureAiGeneration(this.phClient, {
1960
1925
  ...posthogParams,
1961
1926
  model: openAIParams.model,
1962
1927
  provider: 'azure',
@@ -1964,13 +1929,13 @@ class WrappedResponses extends openai.AzureOpenAI.Responses {
1964
1929
  output: [],
1965
1930
  latency: 0,
1966
1931
  baseURL: this.baseURL,
1967
- params: body,
1932
+ modelParameters: getModelParams(body),
1968
1933
  httpStatus,
1969
1934
  usage: {
1970
1935
  inputTokens: 0,
1971
1936
  outputTokens: 0
1972
1937
  },
1973
- error: JSON.stringify(error)
1938
+ error
1974
1939
  });
1975
1940
  throw error;
1976
1941
  });
@@ -1986,8 +1951,7 @@ class WrappedResponses extends openai.AzureOpenAI.Responses {
1986
1951
  const parentPromise = super.parse(openAIParams, options);
1987
1952
  const wrappedPromise = parentPromise.then(async result => {
1988
1953
  const latency = (Date.now() - startTime) / 1000;
1989
- await sendEventToPosthog({
1990
- client: this.phClient,
1954
+ await captureAiGeneration(this.phClient, {
1991
1955
  ...posthogParams,
1992
1956
  model: openAIParams.model ?? result.model,
1993
1957
  provider: 'azure',
@@ -1995,7 +1959,7 @@ class WrappedResponses extends openai.AzureOpenAI.Responses {
1995
1959
  output: result.output,
1996
1960
  latency,
1997
1961
  baseURL: this.baseURL,
1998
- params: body,
1962
+ modelParameters: getModelParams(body),
1999
1963
  httpStatus: 200,
2000
1964
  usage: {
2001
1965
  inputTokens: result.usage?.input_tokens ?? 0,
@@ -2006,8 +1970,7 @@ class WrappedResponses extends openai.AzureOpenAI.Responses {
2006
1970
  });
2007
1971
  return result;
2008
1972
  }, async error => {
2009
- await sendEventToPosthog({
2010
- client: this.phClient,
1973
+ await captureAiGeneration(this.phClient, {
2011
1974
  ...posthogParams,
2012
1975
  model: openAIParams.model,
2013
1976
  provider: 'azure',
@@ -2015,13 +1978,13 @@ class WrappedResponses extends openai.AzureOpenAI.Responses {
2015
1978
  output: [],
2016
1979
  latency: 0,
2017
1980
  baseURL: this.baseURL,
2018
- params: body,
1981
+ modelParameters: getModelParams(body),
2019
1982
  httpStatus: error?.status ? error.status : 500,
2020
1983
  usage: {
2021
1984
  inputTokens: 0,
2022
1985
  outputTokens: 0
2023
1986
  },
2024
- error: JSON.stringify(error)
1987
+ error
2025
1988
  });
2026
1989
  throw error;
2027
1990
  });
@@ -2043,9 +2006,8 @@ class WrappedEmbeddings extends openai.AzureOpenAI.Embeddings {
2043
2006
  const parentPromise = super.create(openAIParams, options);
2044
2007
  const wrappedPromise = parentPromise.then(async result => {
2045
2008
  const latency = (Date.now() - startTime) / 1000;
2046
- await sendEventToPosthog({
2047
- client: this.phClient,
2048
- eventType: AIEvent.Embedding,
2009
+ await captureAiGeneration(this.phClient, {
2010
+ eventType: exports.AIEvent.Embedding,
2049
2011
  ...posthogParams,
2050
2012
  model: openAIParams.model,
2051
2013
  provider: 'azure',
@@ -2054,7 +2016,7 @@ class WrappedEmbeddings extends openai.AzureOpenAI.Embeddings {
2054
2016
  // Embeddings don't have output content
2055
2017
  latency,
2056
2018
  baseURL: this.baseURL,
2057
- params: body,
2019
+ modelParameters: getModelParams(body),
2058
2020
  httpStatus: 200,
2059
2021
  usage: {
2060
2022
  inputTokens: result.usage?.prompt_tokens ?? 0
@@ -2063,9 +2025,8 @@ class WrappedEmbeddings extends openai.AzureOpenAI.Embeddings {
2063
2025
  return result;
2064
2026
  }, async error => {
2065
2027
  const httpStatus = error && typeof error === 'object' && 'status' in error ? error.status ?? 500 : 500;
2066
- await sendEventToPosthog({
2067
- client: this.phClient,
2068
- eventType: AIEvent.Embedding,
2028
+ await captureAiGeneration(this.phClient, {
2029
+ eventType: exports.AIEvent.Embedding,
2069
2030
  ...posthogParams,
2070
2031
  model: openAIParams.model,
2071
2032
  provider: 'azure',
@@ -2073,12 +2034,12 @@ class WrappedEmbeddings extends openai.AzureOpenAI.Embeddings {
2073
2034
  output: null,
2074
2035
  latency: 0,
2075
2036
  baseURL: this.baseURL,
2076
- params: body,
2037
+ modelParameters: getModelParams(body),
2077
2038
  httpStatus,
2078
2039
  usage: {
2079
2040
  inputTokens: 0
2080
2041
  },
2081
- error: JSON.stringify(error)
2042
+ error
2082
2043
  });
2083
2044
  throw error;
2084
2045
  });
@@ -2177,18 +2138,26 @@ const mapVercelPrompt = messages => {
2177
2138
  };
2178
2139
  });
2179
2140
  try {
2180
- // Trim the inputs array until its JSON size fits within MAX_OUTPUT_SIZE
2181
- const encoder = new TextEncoder();
2182
- let serialized = JSON.stringify(inputs);
2141
+ // Trim the inputs array until its serialized JSON size fits within MAX_OUTPUT_SIZE.
2142
+ // Pre-compute each message's byte size once so we can shift by accumulated budget
2143
+ // in a single linear pass, instead of re-stringifying the whole array per iteration.
2144
+ const messageSizes = inputs.map(m => utf8ByteLength(JSON.stringify(m)));
2145
+ // Account for the surrounding `[` `]` plus a comma between each pair of elements.
2146
+ let totalBytes = 2 + Math.max(0, messageSizes.length - 1);
2147
+ for (const size of messageSizes) {
2148
+ totalBytes += size;
2149
+ }
2183
2150
  let removedCount = 0;
2184
- // We need to keep track of the initial size of the inputs array because we're going to be mutating it
2185
- const initialSize = inputs.length;
2186
- for (let i = 0; i < initialSize && encoder.encode(serialized).byteLength > MAX_OUTPUT_SIZE; i++) {
2187
- inputs.shift();
2151
+ while (totalBytes > MAX_OUTPUT_SIZE && removedCount < messageSizes.length) {
2152
+ totalBytes -= messageSizes[removedCount];
2153
+ // Each removed message past the first also drops the comma that joined it.
2154
+ if (removedCount < messageSizes.length - 1) {
2155
+ totalBytes -= 1;
2156
+ }
2188
2157
  removedCount++;
2189
- serialized = JSON.stringify(inputs);
2190
2158
  }
2191
2159
  if (removedCount > 0) {
2160
+ inputs.splice(0, removedCount);
2192
2161
  // Add one placeholder to indicate how many were removed
2193
2162
  inputs.unshift({
2194
2163
  role: 'posthog',
@@ -2407,6 +2376,18 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
2407
2376
  $ai_framework_version: model.specificationVersion === 'v3' ? '6' : '5'
2408
2377
  }
2409
2378
  };
2379
+ // Shared `captureAiGeneration` options for every call site in this wrapper.
2380
+ const baseOptions = {
2381
+ distinctId: mergedOptions.posthogDistinctId,
2382
+ traceId,
2383
+ properties: mergedOptions.posthogProperties,
2384
+ groups: mergedOptions.posthogGroups,
2385
+ privacyMode: mergedOptions.posthogPrivacyMode,
2386
+ modelOverride: mergedOptions.posthogModelOverride,
2387
+ providerOverride: mergedOptions.posthogProviderOverride,
2388
+ costOverride: mergedOptions.posthogCostOverride,
2389
+ captureImmediate: mergedOptions.posthogCaptureImmediate
2390
+ };
2410
2391
  // Create wrapped model using Object.create to preserve the prototype chain
2411
2392
  // This automatically inherits all properties (including getters) from the model
2412
2393
  const wrappedModel = Object.create(model, {
@@ -2459,46 +2440,40 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
2459
2440
  // Extract finish reason - V2 returns a string, V3 returns an object with .unified
2460
2441
  const rawFinishReason = result.finishReason;
2461
2442
  const finishReasonStr = typeof rawFinishReason === 'string' ? rawFinishReason : rawFinishReason && typeof rawFinishReason === 'object' && 'unified' in rawFinishReason ? String(rawFinishReason.unified) : undefined;
2462
- await sendEventToPosthog({
2463
- client: phClient,
2464
- distinctId: mergedOptions.posthogDistinctId,
2465
- traceId: mergedOptions.posthogTraceId ?? uuid.v4(),
2443
+ await captureAiGeneration(phClient, {
2444
+ ...baseOptions,
2466
2445
  model: modelId,
2467
2446
  provider: provider,
2468
2447
  input: mergedOptions.posthogPrivacyMode ? '' : mapVercelPrompt(params.prompt),
2469
2448
  output: content,
2470
2449
  latency,
2471
2450
  baseURL,
2472
- params: mergedParams,
2451
+ modelParameters: getModelParams(mergedParams),
2473
2452
  httpStatus: 200,
2474
2453
  usage,
2475
2454
  stopReason: finishReasonStr,
2476
- tools: availableTools,
2477
- captureImmediate: mergedOptions.posthogCaptureImmediate
2455
+ tools: availableTools
2478
2456
  });
2479
2457
  return result;
2480
2458
  } catch (error) {
2481
2459
  const modelId = model.modelId;
2482
- const enrichedError = await sendEventWithErrorToPosthog({
2483
- client: phClient,
2484
- distinctId: mergedOptions.posthogDistinctId,
2485
- traceId: mergedOptions.posthogTraceId ?? uuid.v4(),
2460
+ await captureAiGeneration(phClient, {
2461
+ ...baseOptions,
2486
2462
  model: modelId,
2487
2463
  provider: model.provider,
2488
2464
  input: mergedOptions.posthogPrivacyMode ? '' : mapVercelPrompt(params.prompt),
2489
2465
  output: [],
2490
2466
  latency: 0,
2491
2467
  baseURL: '',
2492
- params: mergedParams,
2468
+ modelParameters: getModelParams(mergedParams),
2493
2469
  usage: {
2494
2470
  inputTokens: 0,
2495
2471
  outputTokens: 0
2496
2472
  },
2497
2473
  error: error,
2498
- tools: availableTools,
2499
- captureImmediate: mergedOptions.posthogCaptureImmediate
2474
+ tools: availableTools
2500
2475
  });
2501
- throw enrichedError;
2476
+ throw error;
2502
2477
  }
2503
2478
  },
2504
2479
  writable: true,
@@ -2644,10 +2619,8 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
2644
2619
  }
2645
2620
  };
2646
2621
  adjustAnthropicV3CacheTokens(model, modelId, provider, finalUsage);
2647
- await sendEventToPosthog({
2648
- client: phClient,
2649
- distinctId: mergedOptions.posthogDistinctId,
2650
- traceId: mergedOptions.posthogTraceId ?? uuid.v4(),
2622
+ await captureAiGeneration(phClient, {
2623
+ ...baseOptions,
2651
2624
  model: modelId,
2652
2625
  provider: provider,
2653
2626
  input: mergedOptions.posthogPrivacyMode ? '' : mapVercelPrompt(params.prompt),
@@ -2655,12 +2628,11 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
2655
2628
  latency,
2656
2629
  timeToFirstToken,
2657
2630
  baseURL,
2658
- params: mergedParams,
2631
+ modelParameters: getModelParams(mergedParams),
2659
2632
  httpStatus: 200,
2660
2633
  usage: finalUsage,
2661
2634
  stopReason,
2662
- tools: availableTools,
2663
- captureImmediate: mergedOptions.posthogCaptureImmediate
2635
+ tools: availableTools
2664
2636
  });
2665
2637
  }
2666
2638
  });
@@ -2669,26 +2641,23 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
2669
2641
  ...rest
2670
2642
  };
2671
2643
  } catch (error) {
2672
- const enrichedError = await sendEventWithErrorToPosthog({
2673
- client: phClient,
2674
- distinctId: mergedOptions.posthogDistinctId,
2675
- traceId: mergedOptions.posthogTraceId ?? uuid.v4(),
2644
+ await captureAiGeneration(phClient, {
2645
+ ...baseOptions,
2676
2646
  model: modelId,
2677
2647
  provider: provider,
2678
2648
  input: mergedOptions.posthogPrivacyMode ? '' : mapVercelPrompt(params.prompt),
2679
2649
  output: [],
2680
2650
  latency: 0,
2681
2651
  baseURL: '',
2682
- params: mergedParams,
2652
+ modelParameters: getModelParams(mergedParams),
2683
2653
  usage: {
2684
2654
  inputTokens: 0,
2685
2655
  outputTokens: 0
2686
2656
  },
2687
2657
  error: error,
2688
- tools: availableTools,
2689
- captureImmediate: mergedOptions.posthogCaptureImmediate
2658
+ tools: availableTools
2690
2659
  });
2691
- throw enrichedError;
2660
+ throw error;
2692
2661
  }
2693
2662
  },
2694
2663
  writable: true,
@@ -2853,8 +2822,7 @@ class WrappedMessages extends AnthropicOriginal__default.default.Messages {
2853
2822
  text: accumulatedContent
2854
2823
  }]
2855
2824
  }];
2856
- await sendEventToPosthog({
2857
- client: this.phClient,
2825
+ await captureAiGeneration(this.phClient, {
2858
2826
  ...posthogParams,
2859
2827
  model: anthropicParams.model,
2860
2828
  provider: 'anthropic',
@@ -2863,15 +2831,14 @@ class WrappedMessages extends AnthropicOriginal__default.default.Messages {
2863
2831
  latency,
2864
2832
  timeToFirstToken,
2865
2833
  baseURL: this.baseURL,
2866
- params: body,
2834
+ modelParameters: getModelParams(body),
2867
2835
  httpStatus: 200,
2868
2836
  usage,
2869
2837
  stopReason,
2870
2838
  tools: availableTools
2871
2839
  });
2872
2840
  } catch (error) {
2873
- const enrichedError = await sendEventWithErrorToPosthog({
2874
- client: this.phClient,
2841
+ await captureAiGeneration(this.phClient, {
2875
2842
  ...posthogParams,
2876
2843
  model: anthropicParams.model,
2877
2844
  provider: 'anthropic',
@@ -2879,14 +2846,14 @@ class WrappedMessages extends AnthropicOriginal__default.default.Messages {
2879
2846
  output: [],
2880
2847
  latency: 0,
2881
2848
  baseURL: this.baseURL,
2882
- params: body,
2849
+ modelParameters: getModelParams(body),
2883
2850
  usage: {
2884
2851
  inputTokens: 0,
2885
2852
  outputTokens: 0
2886
2853
  },
2887
2854
  error: error
2888
2855
  });
2889
- throw enrichedError;
2856
+ throw error;
2890
2857
  }
2891
2858
  })();
2892
2859
  // Return the other stream to the user
@@ -2899,8 +2866,7 @@ class WrappedMessages extends AnthropicOriginal__default.default.Messages {
2899
2866
  if ('content' in result) {
2900
2867
  const latency = (Date.now() - startTime) / 1000;
2901
2868
  const availableTools = extractAvailableToolCalls('anthropic', anthropicParams);
2902
- await sendEventToPosthog({
2903
- client: this.phClient,
2869
+ await captureAiGeneration(this.phClient, {
2904
2870
  ...posthogParams,
2905
2871
  model: anthropicParams.model,
2906
2872
  provider: 'anthropic',
@@ -2908,7 +2874,7 @@ class WrappedMessages extends AnthropicOriginal__default.default.Messages {
2908
2874
  output: formatResponseAnthropic(result),
2909
2875
  latency,
2910
2876
  baseURL: this.baseURL,
2911
- params: body,
2877
+ modelParameters: getModelParams(body),
2912
2878
  httpStatus: 200,
2913
2879
  usage: {
2914
2880
  inputTokens: result.usage.input_tokens ?? 0,
@@ -2924,8 +2890,7 @@ class WrappedMessages extends AnthropicOriginal__default.default.Messages {
2924
2890
  }
2925
2891
  return result;
2926
2892
  }, async error => {
2927
- await sendEventToPosthog({
2928
- client: this.phClient,
2893
+ await captureAiGeneration(this.phClient, {
2929
2894
  ...posthogParams,
2930
2895
  model: anthropicParams.model,
2931
2896
  provider: 'anthropic',
@@ -2933,13 +2898,13 @@ class WrappedMessages extends AnthropicOriginal__default.default.Messages {
2933
2898
  output: [],
2934
2899
  latency: 0,
2935
2900
  baseURL: this.baseURL,
2936
- params: body,
2901
+ modelParameters: getModelParams(body),
2937
2902
  httpStatus: error?.status ? error.status : 500,
2938
2903
  usage: {
2939
2904
  inputTokens: 0,
2940
2905
  outputTokens: 0
2941
2906
  },
2942
- error: JSON.stringify(error)
2907
+ error: error
2943
2908
  });
2944
2909
  throw error;
2945
2910
  });
@@ -2976,8 +2941,7 @@ class WrappedModels {
2976
2941
  const availableTools = extractAvailableToolCalls('gemini', geminiParams);
2977
2942
  const metadata = response.usageMetadata;
2978
2943
  const finishReason = response.candidates?.[0]?.finishReason;
2979
- await sendEventToPosthog({
2980
- client: this.phClient,
2944
+ await captureAiGeneration(this.phClient, {
2981
2945
  ...posthogParams,
2982
2946
  model: geminiParams.model,
2983
2947
  provider: 'gemini',
@@ -2985,7 +2949,7 @@ class WrappedModels {
2985
2949
  output: formatResponseGemini(response),
2986
2950
  latency,
2987
2951
  baseURL: 'https://generativelanguage.googleapis.com',
2988
- params: params,
2952
+ modelParameters: getModelParams(params),
2989
2953
  httpStatus: 200,
2990
2954
  usage: {
2991
2955
  inputTokens: metadata?.promptTokenCount ?? 0,
@@ -3001,8 +2965,7 @@ class WrappedModels {
3001
2965
  return response;
3002
2966
  } catch (error) {
3003
2967
  const latency = (Date.now() - startTime) / 1000;
3004
- const enrichedError = await sendEventWithErrorToPosthog({
3005
- client: this.phClient,
2968
+ await captureAiGeneration(this.phClient, {
3006
2969
  ...posthogParams,
3007
2970
  model: geminiParams.model,
3008
2971
  provider: 'gemini',
@@ -3010,14 +2973,14 @@ class WrappedModels {
3010
2973
  output: [],
3011
2974
  latency,
3012
2975
  baseURL: 'https://generativelanguage.googleapis.com',
3013
- params: params,
2976
+ modelParameters: getModelParams(params),
3014
2977
  usage: {
3015
2978
  inputTokens: 0,
3016
2979
  outputTokens: 0
3017
2980
  },
3018
- error: error
2981
+ error
3019
2982
  });
3020
- throw enrichedError;
2983
+ throw error;
3021
2984
  }
3022
2985
  }
3023
2986
  async *generateContentStream(params) {
@@ -3116,8 +3079,7 @@ class WrappedModels {
3116
3079
  role: 'assistant',
3117
3080
  content: accumulatedContent
3118
3081
  }] : [];
3119
- await sendEventToPosthog({
3120
- client: this.phClient,
3082
+ await captureAiGeneration(this.phClient, {
3121
3083
  ...posthogParams,
3122
3084
  model: geminiParams.model,
3123
3085
  provider: 'gemini',
@@ -3126,7 +3088,7 @@ class WrappedModels {
3126
3088
  latency,
3127
3089
  timeToFirstToken,
3128
3090
  baseURL: 'https://generativelanguage.googleapis.com',
3129
- params: params,
3091
+ modelParameters: getModelParams(params),
3130
3092
  httpStatus: 200,
3131
3093
  usage: {
3132
3094
  ...usage,
@@ -3138,8 +3100,7 @@ class WrappedModels {
3138
3100
  });
3139
3101
  } catch (error) {
3140
3102
  const latency = (Date.now() - startTime) / 1000;
3141
- const enrichedError = await sendEventWithErrorToPosthog({
3142
- client: this.phClient,
3103
+ await captureAiGeneration(this.phClient, {
3143
3104
  ...posthogParams,
3144
3105
  model: geminiParams.model,
3145
3106
  provider: 'gemini',
@@ -3147,14 +3108,14 @@ class WrappedModels {
3147
3108
  output: [],
3148
3109
  latency,
3149
3110
  baseURL: 'https://generativelanguage.googleapis.com',
3150
- params: params,
3111
+ modelParameters: getModelParams(params),
3151
3112
  usage: {
3152
3113
  inputTokens: 0,
3153
3114
  outputTokens: 0
3154
3115
  },
3155
- error: error
3116
+ error
3156
3117
  });
3157
- throw enrichedError;
3118
+ throw error;
3158
3119
  }
3159
3120
  }
3160
3121
  async embedContent(params) {
@@ -3167,17 +3128,16 @@ class WrappedModels {
3167
3128
  const response = await this.client.models.embedContent(geminiParams);
3168
3129
  const latency = (Date.now() - startTime) / 1000;
3169
3130
  const inputTokens = extractEmbeddingTokenCount(response);
3170
- await sendEventToPosthog({
3171
- client: this.phClient,
3131
+ await captureAiGeneration(this.phClient, {
3172
3132
  ...posthogParams,
3173
- eventType: AIEvent.Embedding,
3133
+ eventType: exports.AIEvent.Embedding,
3174
3134
  model: geminiParams.model,
3175
3135
  provider: 'gemini',
3176
3136
  input: withPrivacyMode(this.phClient, posthogParams.privacyMode ?? false, geminiParams.contents),
3177
3137
  output: null,
3178
3138
  latency,
3179
3139
  baseURL: 'https://generativelanguage.googleapis.com',
3180
- params: params,
3140
+ modelParameters: getModelParams(params),
3181
3141
  httpStatus: 200,
3182
3142
  usage: {
3183
3143
  inputTokens
@@ -3186,23 +3146,22 @@ class WrappedModels {
3186
3146
  return response;
3187
3147
  } catch (error) {
3188
3148
  const latency = (Date.now() - startTime) / 1000;
3189
- const enrichedError = await sendEventWithErrorToPosthog({
3190
- client: this.phClient,
3149
+ await captureAiGeneration(this.phClient, {
3191
3150
  ...posthogParams,
3192
- eventType: AIEvent.Embedding,
3151
+ eventType: exports.AIEvent.Embedding,
3193
3152
  model: geminiParams.model,
3194
3153
  provider: 'gemini',
3195
3154
  input: withPrivacyMode(this.phClient, posthogParams.privacyMode ?? false, geminiParams.contents),
3196
3155
  output: null,
3197
3156
  latency,
3198
3157
  baseURL: 'https://generativelanguage.googleapis.com',
3199
- params: params,
3158
+ modelParameters: getModelParams(params),
3200
3159
  usage: {
3201
3160
  inputTokens: 0
3202
3161
  },
3203
- error: error
3162
+ error
3204
3163
  });
3205
- throw enrichedError;
3164
+ throw error;
3206
3165
  }
3207
3166
  }
3208
3167
  formatPartsAsContentBlocks(parts) {
@@ -4744,5 +4703,6 @@ exports.GoogleGenAI = PostHogGoogleGenAI;
4744
4703
  exports.LangChainCallbackHandler = LangChainCallbackHandler;
4745
4704
  exports.OpenAI = PostHogOpenAI;
4746
4705
  exports.Prompts = Prompts;
4706
+ exports.captureAiGeneration = captureAiGeneration;
4747
4707
  exports.withTracing = wrapVercelLanguageModel;
4748
4708
  //# sourceMappingURL=index.cjs.map