@posthog/ai 8.14.0 → 8.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +35 -1
  2. package/dist/adk/index.cjs +16 -6
  3. package/dist/adk/index.cjs.map +1 -1
  4. package/dist/adk/index.mjs +16 -6
  5. package/dist/adk/index.mjs.map +1 -1
  6. package/dist/anthropic/index.cjs +156 -15
  7. package/dist/anthropic/index.cjs.map +1 -1
  8. package/dist/anthropic/index.d.ts +1 -0
  9. package/dist/anthropic/index.mjs +156 -15
  10. package/dist/anthropic/index.mjs.map +1 -1
  11. package/dist/claude-agent-sdk/index.cjs +111 -37
  12. package/dist/claude-agent-sdk/index.cjs.map +1 -1
  13. package/dist/claude-agent-sdk/index.mjs +111 -37
  14. package/dist/claude-agent-sdk/index.mjs.map +1 -1
  15. package/dist/gemini/index.cjs +175 -39
  16. package/dist/gemini/index.cjs.map +1 -1
  17. package/dist/gemini/index.d.ts +1 -1
  18. package/dist/gemini/index.mjs +175 -39
  19. package/dist/gemini/index.mjs.map +1 -1
  20. package/dist/index.cjs +15 -8
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.mjs +15 -8
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/langchain/index.cjs +15 -5
  25. package/dist/langchain/index.cjs.map +1 -1
  26. package/dist/langchain/index.mjs +15 -5
  27. package/dist/langchain/index.mjs.map +1 -1
  28. package/dist/langchain/middleware/index.cjs +15 -5
  29. package/dist/langchain/middleware/index.cjs.map +1 -1
  30. package/dist/langchain/middleware/index.mjs +15 -5
  31. package/dist/langchain/middleware/index.mjs.map +1 -1
  32. package/dist/openai/index.cjs +169 -13
  33. package/dist/openai/index.cjs.map +1 -1
  34. package/dist/openai/index.mjs +169 -13
  35. package/dist/openai/index.mjs.map +1 -1
  36. package/dist/openai-agents/index.cjs +15 -5
  37. package/dist/openai-agents/index.cjs.map +1 -1
  38. package/dist/openai-agents/index.mjs +15 -5
  39. package/dist/openai-agents/index.mjs.map +1 -1
  40. package/dist/otel/index.cjs +12 -3
  41. package/dist/otel/index.cjs.map +1 -1
  42. package/dist/otel/index.mjs +12 -3
  43. package/dist/otel/index.mjs.map +1 -1
  44. package/dist/vercel/index.cjs +15 -8
  45. package/dist/vercel/index.cjs.map +1 -1
  46. package/dist/vercel/index.mjs +15 -8
  47. package/dist/vercel/index.mjs.map +1 -1
  48. package/package.json +5 -5
@@ -2,6 +2,11 @@ import AnthropicOriginal from "@anthropic-ai/sdk";
2
2
  import { v4 } from "uuid";
3
3
  import { toJsonSafeValue, uuidv7 } from "@posthog/core";
4
4
  import { Stream } from "@anthropic-ai/sdk/streaming";
5
+ //#region src/typeGuards.ts
6
+ const isObject = (value) => {
7
+ return value !== null && typeof value === "object" && !Array.isArray(value);
8
+ };
9
+ //#endregion
5
10
  //#region src/captureAiEvent.ts
6
11
  /** @internal */
7
12
  function isFullAiCaptureEnabled(client) {
@@ -167,17 +172,26 @@ var BinaryContentRedactor = class {
167
172
  this.visited = /* @__PURE__ */ new WeakSet();
168
173
  return this.walk(value, mediaType ? new MediaTypeContext(void 0, void 0, mediaType) : MediaTypeContext.EMPTY);
169
174
  }
175
+ /** Redact one leaf while a caller owns bounded, type-preserving traversal. @internal */
176
+ redactLeaf(value, context) {
177
+ return typeof value === "string" ? this.redactString(value, context) : this.placeholderFor(context.inferMediaType());
178
+ }
170
179
  walk(value, ctx) {
171
180
  if (value === null || value === void 0) return value;
172
- if (typeof value === "string") return this.redactString(value, ctx);
181
+ if (typeof value === "string") return this.redactLeaf(value, ctx);
173
182
  if (typeof value !== "object") return value;
174
- if (typeof Uint8Array !== "undefined" && value instanceof Uint8Array) return this.placeholderFor(ctx.inferMediaType());
183
+ if (typeof Uint8Array !== "undefined" && value instanceof Uint8Array) return this.redactLeaf(value, ctx);
175
184
  if (this.visited.has(value)) return null;
176
185
  this.visited.add(value);
177
186
  if (Array.isArray(value)) return value.map((item) => this.walk(item, ctx));
178
187
  const obj = value;
179
188
  const out = {};
180
- for (const k of Object.keys(obj)) out[k] = this.walk(obj[k], new MediaTypeContext(obj, k));
189
+ for (const k of Object.keys(obj)) Object.defineProperty(out, k, {
190
+ value: this.walk(obj[k], new MediaTypeContext(obj, k)),
191
+ enumerable: true,
192
+ writable: true,
193
+ configurable: true
194
+ });
181
195
  return out;
182
196
  }
183
197
  redactString(value, ctx) {
@@ -199,8 +213,8 @@ var BinaryContentRedactor = class {
199
213
  };
200
214
  //#endregion
201
215
  //#region src/sanitization.ts
202
- const redactor = new BinaryContentRedactor();
203
- const sanitize = (data, client) => isFullAiCaptureEnabled(client) ? data : redactor.redact(data);
216
+ const redactor$1 = new BinaryContentRedactor();
217
+ const sanitize = (data, client) => isFullAiCaptureEnabled(client) ? data : redactor$1.redact(data);
204
218
  const sanitizeAnthropic = (data, client) => sanitize(data, client);
205
219
  //#endregion
206
220
  //#region src/utils.ts
@@ -222,9 +236,10 @@ function hasTokenOverrides(posthogProperties) {
222
236
  function getTokensSource(posthogProperties) {
223
237
  return hasTokenOverrides(posthogProperties) ? "passthrough" : "sdk";
224
238
  }
239
+ const MAX_OUTPUT_SIZE = 2e5;
225
240
  const STRING_FORMAT = "utf8";
226
- new TextEncoder();
227
- new TextDecoder(STRING_FORMAT, { fatal: false });
241
+ const sharedTextEncoder = new TextEncoder();
242
+ const sharedTextDecoder = new TextDecoder(STRING_FORMAT, { fatal: false });
228
243
  const getModelParams = (params, responseServiceTier) => {
229
244
  if (!params) return {};
230
245
  const modelParams = {};
@@ -278,8 +293,27 @@ const mergeSystemPrompt = (params, provider) => {
278
293
  }
279
294
  return params.messages;
280
295
  };
281
- const withPrivacyMode = (client, privacyMode, input) => {
282
- return client.privacy_mode || privacyMode ? null : input;
296
+ const isPrivacyModeEnabled = (client, privacyMode) => Boolean(client.privacy_mode || privacyMode);
297
+ function toSafeString(input) {
298
+ if (input === void 0 || input === null) return "";
299
+ if (typeof input === "string") return input;
300
+ try {
301
+ return JSON.stringify(input);
302
+ } catch {
303
+ console.warn("Failed to stringify input", input);
304
+ return "";
305
+ }
306
+ }
307
+ const truncate = (input, client, maxBytes = MAX_OUTPUT_SIZE) => {
308
+ const str = toSafeString(input);
309
+ if (str === "") return "";
310
+ if (isFullAiCaptureEnabled(client)) return str;
311
+ const buffer = sharedTextEncoder.encode(str);
312
+ if (buffer.length <= maxBytes) return sharedTextDecoder.decode(buffer);
313
+ const truncatedBuffer = buffer.slice(0, maxBytes);
314
+ let truncatedStr = sharedTextDecoder.decode(truncatedBuffer);
315
+ if (truncatedStr.endsWith("�")) truncatedStr = truncatedStr.slice(0, -1);
316
+ return `${truncatedStr}... [truncated]`;
283
317
  };
284
318
  /**
285
319
  * Extract available tool calls from the request parameters.
@@ -340,7 +374,7 @@ function addDefaults(params) {
340
374
  }
341
375
  //#endregion
342
376
  //#region package.json
343
- var version = "8.14.0";
377
+ var version = "8.14.2";
344
378
  //#endregion
345
379
  //#region src/serializeError.ts
346
380
  const DEFAULT_MAX_DEPTH = 3;
@@ -427,7 +461,7 @@ const captureAiGeneration = async (client, options) => {
427
461
  const eventType = options.eventType ?? "$ai_generation";
428
462
  const privacyMode = options.privacyMode ?? false;
429
463
  const usage = options.usage ?? {};
430
- const shouldRedact = withPrivacyMode(client, privacyMode, false) === null;
464
+ const shouldRedact = isPrivacyModeEnabled(client, privacyMode);
431
465
  const safeInput = shouldRedact ? null : toJsonSafeValue(options.input);
432
466
  const safeOutput = shouldRedact ? null : toJsonSafeValue(options.output);
433
467
  let httpStatus = options.httpStatus;
@@ -745,6 +779,89 @@ function monitoredStreamTee(source, createStream) {
745
779
  }), controller)];
746
780
  }
747
781
  //#endregion
782
+ //#region src/toolResult.ts
783
+ const MAX_DEPTH = 20;
784
+ const MAX_ITEMS = 1e3;
785
+ const MAX_NODES = 1e4;
786
+ const TRUNCATED = "[Truncated]";
787
+ const UNSERIALIZABLE = "[Unserializable]";
788
+ const redactor = new BinaryContentRedactor();
789
+ const propertyIsEnumerable = Object.prototype.propertyIsEnumerable;
790
+ /** @internal Preserve tool-result structure while bounding each string value. */
791
+ function formatToolResult(content, client, maxBytes = 5e3) {
792
+ try {
793
+ if (isFullAiCaptureEnabled(client)) return toJsonSafeValue(content);
794
+ const ancestors = /* @__PURE__ */ new WeakSet();
795
+ let remainingNodes = MAX_NODES;
796
+ const convert = (value, depth, context) => {
797
+ if (remainingNodes <= 0) return TRUNCATED;
798
+ remainingNodes--;
799
+ try {
800
+ if (value === null || typeof value !== "object") {
801
+ const safe = toJsonSafeValue(value);
802
+ return typeof safe === "string" ? truncate(redactor.redactLeaf(safe, context), void 0, maxBytes) : safe;
803
+ }
804
+ if (depth >= MAX_DEPTH) return TRUNCATED;
805
+ if (typeof Uint8Array !== "undefined" && value instanceof Uint8Array) return redactor.redactLeaf(value, context);
806
+ if (ancestors.has(value)) return "[Circular]";
807
+ ancestors.add(value);
808
+ try {
809
+ if (value instanceof Date) {
810
+ const safe = toJsonSafeValue(value);
811
+ return typeof safe === "string" ? truncate(redactor.redactLeaf(safe, context), void 0, maxBytes) : safe;
812
+ }
813
+ let hasToJSONResult = false;
814
+ let toJSONResult;
815
+ try {
816
+ const toJSON = value.toJSON;
817
+ if (typeof toJSON === "function") {
818
+ toJSONResult = toJSON.call(value);
819
+ hasToJSONResult = true;
820
+ }
821
+ } catch {}
822
+ if (hasToJSONResult) return convert(toJSONResult, depth + 1, context);
823
+ if (Array.isArray(value)) {
824
+ const output = [];
825
+ const count = Math.min(value.length, MAX_ITEMS);
826
+ let index = 0;
827
+ for (; index < count && remainingNodes > 0; index++) output.push(convert(value[index], depth + 1, context));
828
+ if (value.length > index) output.push(TRUNCATED);
829
+ return output;
830
+ }
831
+ const input = value;
832
+ const output = {};
833
+ let count = 0;
834
+ let truncated = false;
835
+ for (const key in input) {
836
+ if (!propertyIsEnumerable.call(input, key)) break;
837
+ if (count >= MAX_ITEMS || remainingNodes <= 0) {
838
+ truncated = true;
839
+ break;
840
+ }
841
+ const converted = convert(input[key], depth + 1, new MediaTypeContext(input, key));
842
+ Object.defineProperty(output, key, {
843
+ value: converted,
844
+ enumerable: true,
845
+ writable: true,
846
+ configurable: true
847
+ });
848
+ count++;
849
+ }
850
+ if (truncated) output[TRUNCATED] = "Additional properties omitted";
851
+ return output;
852
+ } finally {
853
+ ancestors.delete(value);
854
+ }
855
+ } catch {
856
+ return UNSERIALIZABLE;
857
+ }
858
+ };
859
+ return convert(content, 0, MediaTypeContext.EMPTY);
860
+ } catch {
861
+ return UNSERIALIZABLE;
862
+ }
863
+ }
864
+ //#endregion
748
865
  //#region src/anthropic/index.ts
749
866
  var PostHogAnthropic = class extends AnthropicOriginal {
750
867
  constructor(config) {
@@ -760,6 +877,30 @@ var WrappedMessages = class extends AnthropicOriginal.Messages {
760
877
  this.phClient = phClient;
761
878
  this.baseURL = parentClient.baseURL;
762
879
  }
880
+ formatInputForPostHog(params, privacyMode) {
881
+ try {
882
+ if (isPrivacyModeEnabled(this.phClient, privacyMode)) return null;
883
+ const input = mergeSystemPrompt(params, "anthropic");
884
+ const messages = Array.isArray(input) ? input.map((message) => {
885
+ if (!isObject(message) || !Array.isArray(message.content)) return message;
886
+ const originalContent = message.content;
887
+ const content = originalContent.map((block) => {
888
+ if (isObject(block) && typeof block.type === "string" && (block.type === "tool_result" || block.type.endsWith("_tool_result")) && Object.hasOwn(block, "content")) return {
889
+ ...block,
890
+ content: formatToolResult(block.content, this.phClient, Infinity)
891
+ };
892
+ return block;
893
+ });
894
+ return content.some((block, index) => block !== originalContent[index]) ? {
895
+ ...message,
896
+ content
897
+ } : message;
898
+ }) : input;
899
+ return sanitizeAnthropic(messages, this.phClient);
900
+ } catch {
901
+ return "[Unserializable]";
902
+ }
903
+ }
763
904
  create(body, options) {
764
905
  const { providerParams: anthropicParams, posthogParams } = extractPosthogParams(body);
765
906
  const startTime = Date.now();
@@ -866,7 +1007,7 @@ var WrappedMessages = class extends AnthropicOriginal.Messages {
866
1007
  ...posthogParams,
867
1008
  model: anthropicParams.model,
868
1009
  provider: "anthropic",
869
- input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams, "anthropic"), this.phClient),
1010
+ input: this.formatInputForPostHog(anthropicParams, posthogParams.privacyMode),
870
1011
  output: formattedOutput,
871
1012
  latency,
872
1013
  timeToFirstToken,
@@ -883,7 +1024,7 @@ var WrappedMessages = class extends AnthropicOriginal.Messages {
883
1024
  ...posthogParams,
884
1025
  model: anthropicParams.model,
885
1026
  provider: "anthropic",
886
- input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams, "anthropic"), this.phClient),
1027
+ input: this.formatInputForPostHog(anthropicParams, posthogParams.privacyMode),
887
1028
  output: [],
888
1029
  latency: (Date.now() - startTime) / 1e3,
889
1030
  baseURL: this.baseURL,
@@ -911,7 +1052,7 @@ var WrappedMessages = class extends AnthropicOriginal.Messages {
911
1052
  ...posthogParams,
912
1053
  model: anthropicParams.model,
913
1054
  provider: "anthropic",
914
- input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams, "anthropic"), this.phClient),
1055
+ input: this.formatInputForPostHog(anthropicParams, posthogParams.privacyMode),
915
1056
  output: formatResponseAnthropic(result),
916
1057
  latency,
917
1058
  baseURL: this.baseURL,
@@ -935,7 +1076,7 @@ var WrappedMessages = class extends AnthropicOriginal.Messages {
935
1076
  ...posthogParams,
936
1077
  model: anthropicParams.model,
937
1078
  provider: "anthropic",
938
- input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams, "anthropic"), this.phClient),
1079
+ input: this.formatInputForPostHog(anthropicParams, posthogParams.privacyMode),
939
1080
  output: [],
940
1081
  latency: (Date.now() - startTime) / 1e3,
941
1082
  baseURL: this.baseURL,