@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
@@ -10,6 +10,9 @@ let openai_streaming = require("openai/streaming");
10
10
  const isString = (value) => {
11
11
  return typeof value === "string";
12
12
  };
13
+ const isObject = (value) => {
14
+ return value !== null && typeof value === "object" && !Array.isArray(value);
15
+ };
13
16
  //#endregion
14
17
  //#region src/captureAiEvent.ts
15
18
  /** @internal */
@@ -176,17 +179,26 @@ var BinaryContentRedactor = class {
176
179
  this.visited = /* @__PURE__ */ new WeakSet();
177
180
  return this.walk(value, mediaType ? new MediaTypeContext(void 0, void 0, mediaType) : MediaTypeContext.EMPTY);
178
181
  }
182
+ /** Redact one leaf while a caller owns bounded, type-preserving traversal. @internal */
183
+ redactLeaf(value, context) {
184
+ return typeof value === "string" ? this.redactString(value, context) : this.placeholderFor(context.inferMediaType());
185
+ }
179
186
  walk(value, ctx) {
180
187
  if (value === null || value === void 0) return value;
181
- if (typeof value === "string") return this.redactString(value, ctx);
188
+ if (typeof value === "string") return this.redactLeaf(value, ctx);
182
189
  if (typeof value !== "object") return value;
183
- if (typeof Uint8Array !== "undefined" && value instanceof Uint8Array) return this.placeholderFor(ctx.inferMediaType());
190
+ if (typeof Uint8Array !== "undefined" && value instanceof Uint8Array) return this.redactLeaf(value, ctx);
184
191
  if (this.visited.has(value)) return null;
185
192
  this.visited.add(value);
186
193
  if (Array.isArray(value)) return value.map((item) => this.walk(item, ctx));
187
194
  const obj = value;
188
195
  const out = {};
189
- for (const k of Object.keys(obj)) out[k] = this.walk(obj[k], new MediaTypeContext(obj, k));
196
+ for (const k of Object.keys(obj)) Object.defineProperty(out, k, {
197
+ value: this.walk(obj[k], new MediaTypeContext(obj, k)),
198
+ enumerable: true,
199
+ writable: true,
200
+ configurable: true
201
+ });
190
202
  return out;
191
203
  }
192
204
  redactString(value, ctx) {
@@ -208,8 +220,8 @@ var BinaryContentRedactor = class {
208
220
  };
209
221
  //#endregion
210
222
  //#region src/sanitization.ts
211
- const redactor = new BinaryContentRedactor();
212
- const sanitize = (data, client) => isFullAiCaptureEnabled(client) ? data : redactor.redact(data);
223
+ const redactor$1 = new BinaryContentRedactor();
224
+ const sanitize = (data, client) => isFullAiCaptureEnabled(client) ? data : redactor$1.redact(data);
213
225
  const sanitizeOpenAI = (data, client) => sanitize(data, client);
214
226
  const sanitizeOpenAIResponse = (data, client) => sanitize(data, client);
215
227
  //#endregion
@@ -232,9 +244,10 @@ function hasTokenOverrides(posthogProperties) {
232
244
  function getTokensSource(posthogProperties) {
233
245
  return hasTokenOverrides(posthogProperties) ? "passthrough" : "sdk";
234
246
  }
247
+ const MAX_OUTPUT_SIZE = 2e5;
235
248
  const STRING_FORMAT = "utf8";
236
- new TextEncoder();
237
- new TextDecoder(STRING_FORMAT, { fatal: false });
249
+ const sharedTextEncoder = new TextEncoder();
250
+ const sharedTextDecoder = new TextDecoder(STRING_FORMAT, { fatal: false });
238
251
  /**
239
252
  * Safely converts content to a string, preserving structure for objects/arrays.
240
253
  * - If content is already a string, returns it as-is
@@ -350,8 +363,30 @@ const formatResponseOpenAI = (response) => {
350
363
  }
351
364
  return output;
352
365
  };
366
+ const isPrivacyModeEnabled = (client, privacyMode) => Boolean(client.privacy_mode || privacyMode);
353
367
  const withPrivacyMode = (client, privacyMode, input) => {
354
- return client.privacy_mode || privacyMode ? null : input;
368
+ return isPrivacyModeEnabled(client, privacyMode) ? null : input;
369
+ };
370
+ function toSafeString(input) {
371
+ if (input === void 0 || input === null) return "";
372
+ if (typeof input === "string") return input;
373
+ try {
374
+ return JSON.stringify(input);
375
+ } catch {
376
+ console.warn("Failed to stringify input", input);
377
+ return "";
378
+ }
379
+ }
380
+ const truncate = (input, client, maxBytes = MAX_OUTPUT_SIZE) => {
381
+ const str = toSafeString(input);
382
+ if (str === "") return "";
383
+ if (isFullAiCaptureEnabled(client)) return str;
384
+ const buffer = sharedTextEncoder.encode(str);
385
+ if (buffer.length <= maxBytes) return sharedTextDecoder.decode(buffer);
386
+ const truncatedBuffer = buffer.slice(0, maxBytes);
387
+ let truncatedStr = sharedTextDecoder.decode(truncatedBuffer);
388
+ if (truncatedStr.endsWith("�")) truncatedStr = truncatedStr.slice(0, -1);
389
+ return `${truncatedStr}... [truncated]`;
355
390
  };
356
391
  /**
357
392
  * Calculate web search count from raw API response.
@@ -499,7 +534,7 @@ function formatOpenAIResponsesInput(input, instructions) {
499
534
  }
500
535
  //#endregion
501
536
  //#region package.json
502
- var version = "8.14.0";
537
+ var version = "8.14.2";
503
538
  //#endregion
504
539
  //#region src/serializeError.ts
505
540
  const DEFAULT_MAX_DEPTH = 3;
@@ -586,7 +621,7 @@ const captureAiGeneration$1 = async (client, options) => {
586
621
  const eventType = options.eventType ?? "$ai_generation";
587
622
  const privacyMode = options.privacyMode ?? false;
588
623
  const usage = options.usage ?? {};
589
- const shouldRedact = withPrivacyMode(client, privacyMode, false) === null;
624
+ const shouldRedact = isPrivacyModeEnabled(client, privacyMode);
590
625
  const safeInput = shouldRedact ? null : (0, _posthog_core.toJsonSafeValue)(options.input);
591
626
  const safeOutput = shouldRedact ? null : (0, _posthog_core.toJsonSafeValue)(options.output);
592
627
  let httpStatus = options.httpStatus;
@@ -1217,7 +1252,114 @@ var OpenAIResponsesStreamAccumulator = class {
1217
1252
  }
1218
1253
  };
1219
1254
  //#endregion
1255
+ //#region src/toolResult.ts
1256
+ const MAX_DEPTH = 20;
1257
+ const MAX_ITEMS = 1e3;
1258
+ const MAX_NODES = 1e4;
1259
+ const TRUNCATED = "[Truncated]";
1260
+ const UNSERIALIZABLE = "[Unserializable]";
1261
+ const redactor = new BinaryContentRedactor();
1262
+ const propertyIsEnumerable = Object.prototype.propertyIsEnumerable;
1263
+ /** @internal Preserve tool-result structure while bounding each string value. */
1264
+ function formatToolResult(content, client, maxBytes = 5e3) {
1265
+ try {
1266
+ if (isFullAiCaptureEnabled(client)) return (0, _posthog_core.toJsonSafeValue)(content);
1267
+ const ancestors = /* @__PURE__ */ new WeakSet();
1268
+ let remainingNodes = MAX_NODES;
1269
+ const convert = (value, depth, context) => {
1270
+ if (remainingNodes <= 0) return TRUNCATED;
1271
+ remainingNodes--;
1272
+ try {
1273
+ if (value === null || typeof value !== "object") {
1274
+ const safe = (0, _posthog_core.toJsonSafeValue)(value);
1275
+ return typeof safe === "string" ? truncate(redactor.redactLeaf(safe, context), void 0, maxBytes) : safe;
1276
+ }
1277
+ if (depth >= MAX_DEPTH) return TRUNCATED;
1278
+ if (typeof Uint8Array !== "undefined" && value instanceof Uint8Array) return redactor.redactLeaf(value, context);
1279
+ if (ancestors.has(value)) return "[Circular]";
1280
+ ancestors.add(value);
1281
+ try {
1282
+ if (value instanceof Date) {
1283
+ const safe = (0, _posthog_core.toJsonSafeValue)(value);
1284
+ return typeof safe === "string" ? truncate(redactor.redactLeaf(safe, context), void 0, maxBytes) : safe;
1285
+ }
1286
+ let hasToJSONResult = false;
1287
+ let toJSONResult;
1288
+ try {
1289
+ const toJSON = value.toJSON;
1290
+ if (typeof toJSON === "function") {
1291
+ toJSONResult = toJSON.call(value);
1292
+ hasToJSONResult = true;
1293
+ }
1294
+ } catch {}
1295
+ if (hasToJSONResult) return convert(toJSONResult, depth + 1, context);
1296
+ if (Array.isArray(value)) {
1297
+ const output = [];
1298
+ const count = Math.min(value.length, MAX_ITEMS);
1299
+ let index = 0;
1300
+ for (; index < count && remainingNodes > 0; index++) output.push(convert(value[index], depth + 1, context));
1301
+ if (value.length > index) output.push(TRUNCATED);
1302
+ return output;
1303
+ }
1304
+ const input = value;
1305
+ const output = {};
1306
+ let count = 0;
1307
+ let truncated = false;
1308
+ for (const key in input) {
1309
+ if (!propertyIsEnumerable.call(input, key)) break;
1310
+ if (count >= MAX_ITEMS || remainingNodes <= 0) {
1311
+ truncated = true;
1312
+ break;
1313
+ }
1314
+ const converted = convert(input[key], depth + 1, new MediaTypeContext(input, key));
1315
+ Object.defineProperty(output, key, {
1316
+ value: converted,
1317
+ enumerable: true,
1318
+ writable: true,
1319
+ configurable: true
1320
+ });
1321
+ count++;
1322
+ }
1323
+ if (truncated) output[TRUNCATED] = "Additional properties omitted";
1324
+ return output;
1325
+ } finally {
1326
+ ancestors.delete(value);
1327
+ }
1328
+ } catch {
1329
+ return UNSERIALIZABLE;
1330
+ }
1331
+ };
1332
+ return convert(content, 0, MediaTypeContext.EMPTY);
1333
+ } catch {
1334
+ return UNSERIALIZABLE;
1335
+ }
1336
+ }
1337
+ //#endregion
1220
1338
  //#region src/openai/telemetry.ts
1339
+ const RESPONSE_TOOL_RESULT_TYPES = /* @__PURE__ */ new Set([
1340
+ "function_call_output",
1341
+ "custom_tool_call_output",
1342
+ "computer_call_output",
1343
+ "local_shell_call_output",
1344
+ "shell_call_output",
1345
+ "apply_patch_call_output",
1346
+ "mcp_call"
1347
+ ]);
1348
+ function buildSanitizedChatInput(context) {
1349
+ try {
1350
+ if (isPrivacyModeEnabled(context.client, context.monitoring.privacyMode)) return null;
1351
+ const messages = context.params.messages.map((message) => {
1352
+ if ((message.role === "tool" || message.role === "function") && Object.hasOwn(message, "content")) return {
1353
+ ...message,
1354
+ content: formatToolResult(message.content, context.client, Infinity)
1355
+ };
1356
+ return message;
1357
+ });
1358
+ return sanitizeOpenAI(messages, context.client);
1359
+ } catch {
1360
+ return "[Unserializable]";
1361
+ }
1362
+ }
1221
1363
  function captureAiGenerationInBackground(...args) {
1222
1364
  captureAiGeneration(...args).catch(() => void 0);
1223
1365
  }
@@ -1253,7 +1395,7 @@ function buildChatSuccessOptions(context, result) {
1253
1395
  ...context.monitoring,
1254
1396
  model: context.params.model ?? result.model,
1255
1397
  provider: context.provider,
1256
- input: sanitizeOpenAI(context.params.messages, context.client),
1398
+ input: buildSanitizedChatInput(context),
1257
1399
  output: sanitizeOpenAIResponse(result.output, context.client),
1258
1400
  latency: result.latency,
1259
1401
  timeToFirstToken: result.timeToFirstToken,
@@ -1276,7 +1418,7 @@ function buildChatErrorOptions(context, error, metadata) {
1276
1418
  ...context.monitoring,
1277
1419
  model: context.params.model,
1278
1420
  provider: context.provider,
1279
- input: sanitizeOpenAI(context.params.messages, context.client),
1421
+ input: buildSanitizedChatInput(context),
1280
1422
  output: [],
1281
1423
  latency: metadata.latency,
1282
1424
  baseURL: context.baseURL,
@@ -1288,7 +1430,21 @@ function buildChatErrorOptions(context, error, metadata) {
1288
1430
  };
1289
1431
  }
1290
1432
  function buildSanitizedResponsesInput(context) {
1291
- return formatOpenAIResponsesInput(sanitizeOpenAIResponse(context.params.input, context.client), sanitizeOpenAIResponse(context.params.instructions, context.client));
1433
+ try {
1434
+ if (isPrivacyModeEnabled(context.client, context.monitoring.privacyMode)) return null;
1435
+ const input = Array.isArray(context.params.input) ? context.params.input.map((item) => {
1436
+ if (!isObject(item) || typeof item.type !== "string") return item;
1437
+ const key = RESPONSE_TOOL_RESULT_TYPES.has(item.type) ? "output" : item.type === "code_interpreter_call" ? "outputs" : item.type === "file_search_call" ? "results" : void 0;
1438
+ if (!key || !Object.hasOwn(item, key)) return item;
1439
+ return {
1440
+ ...item,
1441
+ [key]: formatToolResult(item[key], context.client, Infinity)
1442
+ };
1443
+ }) : context.params.input;
1444
+ return formatOpenAIResponsesInput(sanitizeOpenAIResponse(input, context.client), sanitizeOpenAIResponse(context.params.instructions, context.client));
1445
+ } catch {
1446
+ return "[Unserializable]";
1447
+ }
1292
1448
  }
1293
1449
  function buildResponsesSuccessOptions(context, result) {
1294
1450
  const response = result.response;