@posthog/ai 8.14.1 → 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 +2 -2
@@ -6,6 +6,9 @@ import { Stream } from "openai/streaming";
6
6
  const isString = (value) => {
7
7
  return typeof value === "string";
8
8
  };
9
+ const isObject = (value) => {
10
+ return value !== null && typeof value === "object" && !Array.isArray(value);
11
+ };
9
12
  //#endregion
10
13
  //#region src/captureAiEvent.ts
11
14
  /** @internal */
@@ -172,17 +175,26 @@ var BinaryContentRedactor = class {
172
175
  this.visited = /* @__PURE__ */ new WeakSet();
173
176
  return this.walk(value, mediaType ? new MediaTypeContext(void 0, void 0, mediaType) : MediaTypeContext.EMPTY);
174
177
  }
178
+ /** Redact one leaf while a caller owns bounded, type-preserving traversal. @internal */
179
+ redactLeaf(value, context) {
180
+ return typeof value === "string" ? this.redactString(value, context) : this.placeholderFor(context.inferMediaType());
181
+ }
175
182
  walk(value, ctx) {
176
183
  if (value === null || value === void 0) return value;
177
- if (typeof value === "string") return this.redactString(value, ctx);
184
+ if (typeof value === "string") return this.redactLeaf(value, ctx);
178
185
  if (typeof value !== "object") return value;
179
- if (typeof Uint8Array !== "undefined" && value instanceof Uint8Array) return this.placeholderFor(ctx.inferMediaType());
186
+ if (typeof Uint8Array !== "undefined" && value instanceof Uint8Array) return this.redactLeaf(value, ctx);
180
187
  if (this.visited.has(value)) return null;
181
188
  this.visited.add(value);
182
189
  if (Array.isArray(value)) return value.map((item) => this.walk(item, ctx));
183
190
  const obj = value;
184
191
  const out = {};
185
- for (const k of Object.keys(obj)) out[k] = this.walk(obj[k], new MediaTypeContext(obj, k));
192
+ for (const k of Object.keys(obj)) Object.defineProperty(out, k, {
193
+ value: this.walk(obj[k], new MediaTypeContext(obj, k)),
194
+ enumerable: true,
195
+ writable: true,
196
+ configurable: true
197
+ });
186
198
  return out;
187
199
  }
188
200
  redactString(value, ctx) {
@@ -204,8 +216,8 @@ var BinaryContentRedactor = class {
204
216
  };
205
217
  //#endregion
206
218
  //#region src/sanitization.ts
207
- const redactor = new BinaryContentRedactor();
208
- const sanitize = (data, client) => isFullAiCaptureEnabled(client) ? data : redactor.redact(data);
219
+ const redactor$1 = new BinaryContentRedactor();
220
+ const sanitize = (data, client) => isFullAiCaptureEnabled(client) ? data : redactor$1.redact(data);
209
221
  const sanitizeOpenAI = (data, client) => sanitize(data, client);
210
222
  const sanitizeOpenAIResponse = (data, client) => sanitize(data, client);
211
223
  //#endregion
@@ -228,9 +240,10 @@ function hasTokenOverrides(posthogProperties) {
228
240
  function getTokensSource(posthogProperties) {
229
241
  return hasTokenOverrides(posthogProperties) ? "passthrough" : "sdk";
230
242
  }
243
+ const MAX_OUTPUT_SIZE = 2e5;
231
244
  const STRING_FORMAT = "utf8";
232
- new TextEncoder();
233
- new TextDecoder(STRING_FORMAT, { fatal: false });
245
+ const sharedTextEncoder = new TextEncoder();
246
+ const sharedTextDecoder = new TextDecoder(STRING_FORMAT, { fatal: false });
234
247
  /**
235
248
  * Safely converts content to a string, preserving structure for objects/arrays.
236
249
  * - If content is already a string, returns it as-is
@@ -346,8 +359,30 @@ const formatResponseOpenAI = (response) => {
346
359
  }
347
360
  return output;
348
361
  };
362
+ const isPrivacyModeEnabled = (client, privacyMode) => Boolean(client.privacy_mode || privacyMode);
349
363
  const withPrivacyMode = (client, privacyMode, input) => {
350
- return client.privacy_mode || privacyMode ? null : input;
364
+ return isPrivacyModeEnabled(client, privacyMode) ? null : input;
365
+ };
366
+ function toSafeString(input) {
367
+ if (input === void 0 || input === null) return "";
368
+ if (typeof input === "string") return input;
369
+ try {
370
+ return JSON.stringify(input);
371
+ } catch {
372
+ console.warn("Failed to stringify input", input);
373
+ return "";
374
+ }
375
+ }
376
+ const truncate = (input, client, maxBytes = MAX_OUTPUT_SIZE) => {
377
+ const str = toSafeString(input);
378
+ if (str === "") return "";
379
+ if (isFullAiCaptureEnabled(client)) return str;
380
+ const buffer = sharedTextEncoder.encode(str);
381
+ if (buffer.length <= maxBytes) return sharedTextDecoder.decode(buffer);
382
+ const truncatedBuffer = buffer.slice(0, maxBytes);
383
+ let truncatedStr = sharedTextDecoder.decode(truncatedBuffer);
384
+ if (truncatedStr.endsWith("�")) truncatedStr = truncatedStr.slice(0, -1);
385
+ return `${truncatedStr}... [truncated]`;
351
386
  };
352
387
  /**
353
388
  * Calculate web search count from raw API response.
@@ -495,7 +530,7 @@ function formatOpenAIResponsesInput(input, instructions) {
495
530
  }
496
531
  //#endregion
497
532
  //#region package.json
498
- var version = "8.14.1";
533
+ var version = "8.14.2";
499
534
  //#endregion
500
535
  //#region src/serializeError.ts
501
536
  const DEFAULT_MAX_DEPTH = 3;
@@ -582,7 +617,7 @@ const captureAiGeneration$1 = async (client, options) => {
582
617
  const eventType = options.eventType ?? "$ai_generation";
583
618
  const privacyMode = options.privacyMode ?? false;
584
619
  const usage = options.usage ?? {};
585
- const shouldRedact = withPrivacyMode(client, privacyMode, false) === null;
620
+ const shouldRedact = isPrivacyModeEnabled(client, privacyMode);
586
621
  const safeInput = shouldRedact ? null : toJsonSafeValue(options.input);
587
622
  const safeOutput = shouldRedact ? null : toJsonSafeValue(options.output);
588
623
  let httpStatus = options.httpStatus;
@@ -1213,7 +1248,114 @@ var OpenAIResponsesStreamAccumulator = class {
1213
1248
  }
1214
1249
  };
1215
1250
  //#endregion
1251
+ //#region src/toolResult.ts
1252
+ const MAX_DEPTH = 20;
1253
+ const MAX_ITEMS = 1e3;
1254
+ const MAX_NODES = 1e4;
1255
+ const TRUNCATED = "[Truncated]";
1256
+ const UNSERIALIZABLE = "[Unserializable]";
1257
+ const redactor = new BinaryContentRedactor();
1258
+ const propertyIsEnumerable = Object.prototype.propertyIsEnumerable;
1259
+ /** @internal Preserve tool-result structure while bounding each string value. */
1260
+ function formatToolResult(content, client, maxBytes = 5e3) {
1261
+ try {
1262
+ if (isFullAiCaptureEnabled(client)) return toJsonSafeValue(content);
1263
+ const ancestors = /* @__PURE__ */ new WeakSet();
1264
+ let remainingNodes = MAX_NODES;
1265
+ const convert = (value, depth, context) => {
1266
+ if (remainingNodes <= 0) return TRUNCATED;
1267
+ remainingNodes--;
1268
+ try {
1269
+ if (value === null || typeof value !== "object") {
1270
+ const safe = toJsonSafeValue(value);
1271
+ return typeof safe === "string" ? truncate(redactor.redactLeaf(safe, context), void 0, maxBytes) : safe;
1272
+ }
1273
+ if (depth >= MAX_DEPTH) return TRUNCATED;
1274
+ if (typeof Uint8Array !== "undefined" && value instanceof Uint8Array) return redactor.redactLeaf(value, context);
1275
+ if (ancestors.has(value)) return "[Circular]";
1276
+ ancestors.add(value);
1277
+ try {
1278
+ if (value instanceof Date) {
1279
+ const safe = toJsonSafeValue(value);
1280
+ return typeof safe === "string" ? truncate(redactor.redactLeaf(safe, context), void 0, maxBytes) : safe;
1281
+ }
1282
+ let hasToJSONResult = false;
1283
+ let toJSONResult;
1284
+ try {
1285
+ const toJSON = value.toJSON;
1286
+ if (typeof toJSON === "function") {
1287
+ toJSONResult = toJSON.call(value);
1288
+ hasToJSONResult = true;
1289
+ }
1290
+ } catch {}
1291
+ if (hasToJSONResult) return convert(toJSONResult, depth + 1, context);
1292
+ if (Array.isArray(value)) {
1293
+ const output = [];
1294
+ const count = Math.min(value.length, MAX_ITEMS);
1295
+ let index = 0;
1296
+ for (; index < count && remainingNodes > 0; index++) output.push(convert(value[index], depth + 1, context));
1297
+ if (value.length > index) output.push(TRUNCATED);
1298
+ return output;
1299
+ }
1300
+ const input = value;
1301
+ const output = {};
1302
+ let count = 0;
1303
+ let truncated = false;
1304
+ for (const key in input) {
1305
+ if (!propertyIsEnumerable.call(input, key)) break;
1306
+ if (count >= MAX_ITEMS || remainingNodes <= 0) {
1307
+ truncated = true;
1308
+ break;
1309
+ }
1310
+ const converted = convert(input[key], depth + 1, new MediaTypeContext(input, key));
1311
+ Object.defineProperty(output, key, {
1312
+ value: converted,
1313
+ enumerable: true,
1314
+ writable: true,
1315
+ configurable: true
1316
+ });
1317
+ count++;
1318
+ }
1319
+ if (truncated) output[TRUNCATED] = "Additional properties omitted";
1320
+ return output;
1321
+ } finally {
1322
+ ancestors.delete(value);
1323
+ }
1324
+ } catch {
1325
+ return UNSERIALIZABLE;
1326
+ }
1327
+ };
1328
+ return convert(content, 0, MediaTypeContext.EMPTY);
1329
+ } catch {
1330
+ return UNSERIALIZABLE;
1331
+ }
1332
+ }
1333
+ //#endregion
1216
1334
  //#region src/openai/telemetry.ts
1335
+ const RESPONSE_TOOL_RESULT_TYPES = /* @__PURE__ */ new Set([
1336
+ "function_call_output",
1337
+ "custom_tool_call_output",
1338
+ "computer_call_output",
1339
+ "local_shell_call_output",
1340
+ "shell_call_output",
1341
+ "apply_patch_call_output",
1342
+ "mcp_call"
1343
+ ]);
1344
+ function buildSanitizedChatInput(context) {
1345
+ try {
1346
+ if (isPrivacyModeEnabled(context.client, context.monitoring.privacyMode)) return null;
1347
+ const messages = context.params.messages.map((message) => {
1348
+ if ((message.role === "tool" || message.role === "function") && Object.hasOwn(message, "content")) return {
1349
+ ...message,
1350
+ content: formatToolResult(message.content, context.client, Infinity)
1351
+ };
1352
+ return message;
1353
+ });
1354
+ return sanitizeOpenAI(messages, context.client);
1355
+ } catch {
1356
+ return "[Unserializable]";
1357
+ }
1358
+ }
1217
1359
  function captureAiGenerationInBackground(...args) {
1218
1360
  captureAiGeneration(...args).catch(() => void 0);
1219
1361
  }
@@ -1249,7 +1391,7 @@ function buildChatSuccessOptions(context, result) {
1249
1391
  ...context.monitoring,
1250
1392
  model: context.params.model ?? result.model,
1251
1393
  provider: context.provider,
1252
- input: sanitizeOpenAI(context.params.messages, context.client),
1394
+ input: buildSanitizedChatInput(context),
1253
1395
  output: sanitizeOpenAIResponse(result.output, context.client),
1254
1396
  latency: result.latency,
1255
1397
  timeToFirstToken: result.timeToFirstToken,
@@ -1272,7 +1414,7 @@ function buildChatErrorOptions(context, error, metadata) {
1272
1414
  ...context.monitoring,
1273
1415
  model: context.params.model,
1274
1416
  provider: context.provider,
1275
- input: sanitizeOpenAI(context.params.messages, context.client),
1417
+ input: buildSanitizedChatInput(context),
1276
1418
  output: [],
1277
1419
  latency: metadata.latency,
1278
1420
  baseURL: context.baseURL,
@@ -1284,7 +1426,21 @@ function buildChatErrorOptions(context, error, metadata) {
1284
1426
  };
1285
1427
  }
1286
1428
  function buildSanitizedResponsesInput(context) {
1287
- return formatOpenAIResponsesInput(sanitizeOpenAIResponse(context.params.input, context.client), sanitizeOpenAIResponse(context.params.instructions, context.client));
1429
+ try {
1430
+ if (isPrivacyModeEnabled(context.client, context.monitoring.privacyMode)) return null;
1431
+ const input = Array.isArray(context.params.input) ? context.params.input.map((item) => {
1432
+ if (!isObject(item) || typeof item.type !== "string") return item;
1433
+ const key = RESPONSE_TOOL_RESULT_TYPES.has(item.type) ? "output" : item.type === "code_interpreter_call" ? "outputs" : item.type === "file_search_call" ? "results" : void 0;
1434
+ if (!key || !Object.hasOwn(item, key)) return item;
1435
+ return {
1436
+ ...item,
1437
+ [key]: formatToolResult(item[key], context.client, Infinity)
1438
+ };
1439
+ }) : context.params.input;
1440
+ return formatOpenAIResponsesInput(sanitizeOpenAIResponse(input, context.client), sanitizeOpenAIResponse(context.params.instructions, context.client));
1441
+ } catch {
1442
+ return "[Unserializable]";
1443
+ }
1288
1444
  }
1289
1445
  function buildResponsesSuccessOptions(context, result) {
1290
1446
  const response = result.response;