@posthog/ai 8.16.1 → 8.16.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.
- package/README.md +12 -0
- package/dist/adk/index.cjs +147 -9
- package/dist/adk/index.cjs.map +1 -1
- package/dist/adk/index.mjs +147 -9
- package/dist/adk/index.mjs.map +1 -1
- package/dist/anthropic/index.cjs +141 -8
- package/dist/anthropic/index.cjs.map +1 -1
- package/dist/anthropic/index.mjs +141 -8
- package/dist/anthropic/index.mjs.map +1 -1
- package/dist/claude-agent-sdk/index.cjs +147 -9
- package/dist/claude-agent-sdk/index.cjs.map +1 -1
- package/dist/claude-agent-sdk/index.mjs +147 -9
- package/dist/claude-agent-sdk/index.mjs.map +1 -1
- package/dist/gemini/index.cjs +141 -8
- package/dist/gemini/index.cjs.map +1 -1
- package/dist/gemini/index.mjs +141 -8
- package/dist/gemini/index.mjs.map +1 -1
- package/dist/index.cjs +149 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +149 -15
- package/dist/index.mjs.map +1 -1
- package/dist/langchain/index.cjs +141 -7
- package/dist/langchain/index.cjs.map +1 -1
- package/dist/langchain/index.d.ts +1 -0
- package/dist/langchain/index.mjs +141 -7
- package/dist/langchain/index.mjs.map +1 -1
- package/dist/langchain/middleware/index.cjs +150 -11
- package/dist/langchain/middleware/index.cjs.map +1 -1
- package/dist/langchain/middleware/index.mjs +150 -11
- package/dist/langchain/middleware/index.mjs.map +1 -1
- package/dist/openai/index.cjs +141 -8
- package/dist/openai/index.cjs.map +1 -1
- package/dist/openai/index.mjs +141 -8
- package/dist/openai/index.mjs.map +1 -1
- package/dist/openai-agents/index.cjs +104 -3
- package/dist/openai-agents/index.cjs.map +1 -1
- package/dist/openai-agents/index.mjs +104 -3
- package/dist/openai-agents/index.mjs.map +1 -1
- package/dist/otel/index.cjs +216 -4
- package/dist/otel/index.cjs.map +1 -1
- package/dist/otel/index.d.ts +22 -1
- package/dist/otel/index.mjs +216 -4
- package/dist/otel/index.mjs.map +1 -1
- package/dist/vercel/index.cjs +149 -15
- package/dist/vercel/index.cjs.map +1 -1
- package/dist/vercel/index.mjs +149 -15
- package/dist/vercel/index.mjs.map +1 -1
- package/package.json +3 -3
|
@@ -219,6 +219,10 @@ const redactor = new BinaryContentRedactor();
|
|
|
219
219
|
const sanitize = (data, client) => isFullAiCaptureEnabled(client) ? data : redactor.redact(data);
|
|
220
220
|
const sanitizeLangChain = (data, client) => sanitize(data, client);
|
|
221
221
|
//#endregion
|
|
222
|
+
//#region src/privacyMode.ts
|
|
223
|
+
/** Per-call settings can turn redaction on but never off. */
|
|
224
|
+
const isPrivacyModeEnabled = (client, privacyMode = false) => privacyMode === true || client?.privacyMode === true || client?.privacy_mode === true || client?.options?.privacyMode === true;
|
|
225
|
+
//#endregion
|
|
222
226
|
//#region src/utils.ts
|
|
223
227
|
const STRING_FORMAT = "utf8";
|
|
224
228
|
new TextEncoder();
|
|
@@ -268,7 +272,6 @@ const getModelParams = (params, responseServiceTier) => {
|
|
|
268
272
|
if (responseServiceTier != null) modelParams.service_tier = responseServiceTier;
|
|
269
273
|
return modelParams;
|
|
270
274
|
};
|
|
271
|
-
const isPrivacyModeEnabled = (client, privacyMode) => Boolean(client.privacy_mode || privacyMode);
|
|
272
275
|
const withPrivacyMode = (client, privacyMode, input) => {
|
|
273
276
|
return isPrivacyModeEnabled(client, privacyMode) ? null : input;
|
|
274
277
|
};
|
|
@@ -281,12 +284,40 @@ function sanitizeValues(obj) {
|
|
|
281
284
|
return jsonSafe;
|
|
282
285
|
}
|
|
283
286
|
//#endregion
|
|
287
|
+
//#region src/mcpCredentials.ts
|
|
288
|
+
const MCP_CREDENTIAL_FIELDS = ["headers", "authorization"];
|
|
289
|
+
const MCP_PROVIDER_TOOL_IDS = /* @__PURE__ */ new Set([
|
|
290
|
+
"openai.mcp",
|
|
291
|
+
"xai.mcp",
|
|
292
|
+
"google.mcp_server"
|
|
293
|
+
]);
|
|
294
|
+
const isMcpProviderTool = (tool) => (tool.type === "provider" || tool.type === "provider-defined") && typeof tool.id === "string" && MCP_PROVIDER_TOOL_IDS.has(tool.id);
|
|
295
|
+
const withoutMcpCredentials = (config) => {
|
|
296
|
+
const redacted = { ...config };
|
|
297
|
+
for (const field of MCP_CREDENTIAL_FIELDS) if (field in redacted) redacted[field] = "[REDACTED]";
|
|
298
|
+
return redacted;
|
|
299
|
+
};
|
|
300
|
+
/** Hides the credentials of a remote MCP tool definition; everything else is kept as sent. */
|
|
301
|
+
function redactMcpToolDefinition(tool) {
|
|
302
|
+
if (!isObject(tool)) return tool;
|
|
303
|
+
if (tool.type === "mcp") return withoutMcpCredentials(tool);
|
|
304
|
+
if (isMcpProviderTool(tool) && isObject(tool.args)) return {
|
|
305
|
+
...tool,
|
|
306
|
+
args: withoutMcpCredentials(tool.args)
|
|
307
|
+
};
|
|
308
|
+
return tool;
|
|
309
|
+
}
|
|
310
|
+
function redactMcpToolCredentials(tools) {
|
|
311
|
+
return Array.isArray(tools) ? tools.map(redactMcpToolDefinition) : tools;
|
|
312
|
+
}
|
|
313
|
+
//#endregion
|
|
284
314
|
//#region package.json
|
|
285
|
-
var version = "8.16.
|
|
315
|
+
var version = "8.16.2";
|
|
286
316
|
//#endregion
|
|
287
317
|
//#region src/serializeError.ts
|
|
288
318
|
const DEFAULT_MAX_DEPTH = 3;
|
|
289
319
|
const MAX_STACK_LINES = 20;
|
|
320
|
+
const OMITTED_FIELD = "requestBodyValues";
|
|
290
321
|
function serializeError(value, depth = DEFAULT_MAX_DEPTH) {
|
|
291
322
|
if (depth < 0 || value === null || typeof value !== "object") return value;
|
|
292
323
|
if (value instanceof Error) {
|
|
@@ -295,16 +326,17 @@ function serializeError(value, depth = DEFAULT_MAX_DEPTH) {
|
|
|
295
326
|
message: value.message,
|
|
296
327
|
stack: truncateStack(value.stack)
|
|
297
328
|
};
|
|
298
|
-
for (const key of Object.keys(value)) out[key] = serializeError(value
|
|
329
|
+
for (const key of Object.keys(value)) if (key !== OMITTED_FIELD) out[key] = serializeError(Reflect.get(value, key), depth - 1);
|
|
299
330
|
if (value.cause !== void 0) out.cause = serializeError(value.cause, depth - 1);
|
|
300
331
|
return out;
|
|
301
332
|
}
|
|
302
333
|
if (Array.isArray(value)) return value.map((item) => serializeError(item, depth - 1));
|
|
303
334
|
return value;
|
|
304
335
|
}
|
|
336
|
+
const omitRequestBody = (key, value) => key === OMITTED_FIELD ? void 0 : value;
|
|
305
337
|
function stringifyError(error) {
|
|
306
338
|
try {
|
|
307
|
-
return JSON.stringify(sanitizeValues(serializeError(error)));
|
|
339
|
+
return JSON.stringify(sanitizeValues(serializeError(error)), omitRequestBody);
|
|
308
340
|
} catch {
|
|
309
341
|
if (error instanceof Error) return JSON.stringify({
|
|
310
342
|
name: error.name,
|
|
@@ -313,6 +345,105 @@ function stringifyError(error) {
|
|
|
313
345
|
return JSON.stringify({ message: String(error) });
|
|
314
346
|
}
|
|
315
347
|
}
|
|
348
|
+
const CLASS_NAME = /^[A-Za-z_$][A-Za-z0-9_$.]{0,127}$/;
|
|
349
|
+
const PROVIDER_CODE = /^[A-Za-z0-9_.:-]{1,64}$/;
|
|
350
|
+
const PARAM = /^[A-Za-z0-9_.[\]-]{1,128}$/;
|
|
351
|
+
const REQUEST_ID = /^[A-Za-z0-9_.:-]{1,128}$/;
|
|
352
|
+
const MAX_CAUSES = 3;
|
|
353
|
+
const readField = (value, key) => {
|
|
354
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") return;
|
|
355
|
+
try {
|
|
356
|
+
return Reflect.get(value, key);
|
|
357
|
+
} catch {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
const matching = (value, grammar) => typeof value === "string" && grammar.test(value) ? value : void 0;
|
|
362
|
+
const firstMatching = (values, grammar) => {
|
|
363
|
+
for (const value of values) {
|
|
364
|
+
const match = matching(value, grammar);
|
|
365
|
+
if (match !== void 0) return match;
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
const className = (value) => {
|
|
369
|
+
if (!(value instanceof Error)) return "NonErrorThrown";
|
|
370
|
+
const name = readField(value, "name");
|
|
371
|
+
return firstMatching([
|
|
372
|
+
name === "Error" ? void 0 : name,
|
|
373
|
+
readField(readField(value, "constructor"), "name"),
|
|
374
|
+
name
|
|
375
|
+
], CLASS_NAME) ?? "Error";
|
|
376
|
+
};
|
|
377
|
+
const httpStatus = (error) => {
|
|
378
|
+
for (const key of ["status", "statusCode"]) {
|
|
379
|
+
const value = readField(error, key);
|
|
380
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599) return value;
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
const unwrapEnvelope = (body) => {
|
|
384
|
+
const inner = readField(body, "error");
|
|
385
|
+
return inner !== null && typeof inner === "object" ? inner : body;
|
|
386
|
+
};
|
|
387
|
+
const parsedResponseBody = (error) => {
|
|
388
|
+
const responseBody = readField(error, "responseBody");
|
|
389
|
+
if (typeof responseBody !== "string") return;
|
|
390
|
+
try {
|
|
391
|
+
return unwrapEnvelope(JSON.parse(responseBody));
|
|
392
|
+
} catch {
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
const causeNames = (error) => {
|
|
397
|
+
const names = [];
|
|
398
|
+
let cause = readField(error, "cause");
|
|
399
|
+
while (cause !== void 0 && cause !== null && names.length < MAX_CAUSES) {
|
|
400
|
+
names.push(className(cause));
|
|
401
|
+
cause = readField(cause, "cause");
|
|
402
|
+
}
|
|
403
|
+
return names;
|
|
404
|
+
};
|
|
405
|
+
const describeError = (error) => {
|
|
406
|
+
const sources = [
|
|
407
|
+
error,
|
|
408
|
+
unwrapEnvelope(readField(error, "error")),
|
|
409
|
+
parsedResponseBody(error)
|
|
410
|
+
];
|
|
411
|
+
const codes = /* @__PURE__ */ new Set();
|
|
412
|
+
for (const source of sources) for (const key of [
|
|
413
|
+
"code",
|
|
414
|
+
"type",
|
|
415
|
+
"status"
|
|
416
|
+
]) {
|
|
417
|
+
const code = matching(readField(source, key), PROVIDER_CODE);
|
|
418
|
+
if (code !== void 0) codes.add(code);
|
|
419
|
+
}
|
|
420
|
+
const status = httpStatus(error);
|
|
421
|
+
const param = firstMatching(sources.map((source) => readField(source, "param")), PARAM);
|
|
422
|
+
const requestId = firstMatching([readField(error, "requestID"), readField(error, "request_id")], REQUEST_ID);
|
|
423
|
+
const causes = causeNames(error);
|
|
424
|
+
let summary = className(error);
|
|
425
|
+
if (status !== void 0) summary += `: ${status}`;
|
|
426
|
+
for (const code of codes) summary += ` ${code}`;
|
|
427
|
+
if (param !== void 0) summary += ` param=${param}`;
|
|
428
|
+
if (requestId !== void 0) summary += ` request_id=${requestId}`;
|
|
429
|
+
if (causes.length > 0) summary += ` (caused by ${causes.join(", ")})`;
|
|
430
|
+
return summary;
|
|
431
|
+
};
|
|
432
|
+
/**
|
|
433
|
+
* Describes an error for `$ai_error` without its message, stack, or arbitrary fields, which
|
|
434
|
+
* routinely echo the prompt. Only structured fields that pass a strict grammar are kept.
|
|
435
|
+
* The format matches the Python SDK.
|
|
436
|
+
*/
|
|
437
|
+
function summarizeErrorForPrivacy(error) {
|
|
438
|
+
try {
|
|
439
|
+
return describeError(error);
|
|
440
|
+
} catch {
|
|
441
|
+
return error instanceof Error ? "Error" : "NonErrorThrown";
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
function formatAiError(error, privacyMode) {
|
|
445
|
+
return privacyMode ? summarizeErrorForPrivacy(error) : stringifyError(error);
|
|
446
|
+
}
|
|
316
447
|
function truncateStack(stack) {
|
|
317
448
|
if (!stack) return stack;
|
|
318
449
|
const lines = stack.split("\n");
|
|
@@ -563,6 +694,9 @@ var LangChainCallbackHandler = class extends BaseCallbackHandler {
|
|
|
563
694
|
if (parentRunId && !this.parentTree[parentRunId]) return traceId;
|
|
564
695
|
return parentRunId;
|
|
565
696
|
}
|
|
697
|
+
_isPrivacyModeEnabled() {
|
|
698
|
+
return isPrivacyModeEnabled(this.client, this.privacyMode);
|
|
699
|
+
}
|
|
566
700
|
_safeCapture(message) {
|
|
567
701
|
try {
|
|
568
702
|
captureAiEvent(this.client, message);
|
|
@@ -602,7 +736,7 @@ var LangChainCallbackHandler = class extends BaseCallbackHandler {
|
|
|
602
736
|
const interrupts = outputs.interrupts;
|
|
603
737
|
if (interrupts !== void 0) eventProperties["$ai_output_state"] = withPrivacyMode(this.client, this.privacyMode, sanitizeLangChain({ __interrupt__: interrupts }, this.client));
|
|
604
738
|
} else {
|
|
605
|
-
eventProperties["$ai_error"] =
|
|
739
|
+
eventProperties["$ai_error"] = formatAiError(outputs, this._isPrivacyModeEnabled());
|
|
606
740
|
eventProperties["$ai_is_error"] = true;
|
|
607
741
|
}
|
|
608
742
|
} else if (outputs !== void 0) eventProperties["$ai_output_state"] = withPrivacyMode(this.client, this.privacyMode, sanitizeLangChain(outputs, this.client));
|
|
@@ -651,10 +785,10 @@ var LangChainCallbackHandler = class extends BaseCallbackHandler {
|
|
|
651
785
|
...eventPropertiesServedTier
|
|
652
786
|
};
|
|
653
787
|
if (parentRunId) eventProperties["$ai_parent_id"] = parentRunId;
|
|
654
|
-
if (run.tools) eventProperties["$ai_tools"] = run.tools;
|
|
788
|
+
if (run.tools) eventProperties["$ai_tools"] = redactMcpToolCredentials(run.tools);
|
|
655
789
|
if (output instanceof Error) {
|
|
656
790
|
eventProperties["$ai_http_status"] = output.status || 500;
|
|
657
|
-
eventProperties["$ai_error"] =
|
|
791
|
+
eventProperties["$ai_error"] = formatAiError(output, this._isPrivacyModeEnabled());
|
|
658
792
|
eventProperties["$ai_is_error"] = true;
|
|
659
793
|
} else {
|
|
660
794
|
const [inputTokens, outputTokens, additionalTokenData] = this.parseUsage(output, run.provider, run.model);
|
|
@@ -949,7 +1083,11 @@ const stringify = (value) => {
|
|
|
949
1083
|
}
|
|
950
1084
|
}
|
|
951
1085
|
};
|
|
952
|
-
const toError = (error) =>
|
|
1086
|
+
const toError = (error, privacyMode) => {
|
|
1087
|
+
if (error instanceof Error) return error;
|
|
1088
|
+
return privacyMode ? Object.assign(/* @__PURE__ */ new Error(), { name: "NonErrorThrown" }) : new Error(stringify(error));
|
|
1089
|
+
};
|
|
1090
|
+
const toolMessageError = (message, privacyMode) => new Error(privacyMode ? "Tool returned an error" : toContentString(message.content));
|
|
953
1091
|
const safely = (callback) => {
|
|
954
1092
|
try {
|
|
955
1093
|
callback();
|
|
@@ -1024,6 +1162,7 @@ const toLLMResult = (response) => {
|
|
|
1024
1162
|
const createPostHogMiddleware = (options) => {
|
|
1025
1163
|
const { stateSchema, ...callbackOptions } = options;
|
|
1026
1164
|
const callback = new LangChainMiddlewareCallbackHandler(callbackOptions);
|
|
1165
|
+
const privacyMode = () => isPrivacyModeEnabled(callbackOptions.client, callbackOptions.privacyMode);
|
|
1027
1166
|
const middlewareStateSchema = stateSchema ? extendInteropZodObject(stateSchema, postHogStateSchema.shape) : postHogStateSchema;
|
|
1028
1167
|
return createMiddleware({
|
|
1029
1168
|
name: "PostHogMiddleware",
|
|
@@ -1065,7 +1204,7 @@ const createPostHogMiddleware = (options) => {
|
|
|
1065
1204
|
safely(() => callback.handleLLMEnd(toLLMResult(response), runId, parentRunId));
|
|
1066
1205
|
return response;
|
|
1067
1206
|
} catch (error) {
|
|
1068
|
-
safely(() => callback.handleLLMError(toError(error), runId));
|
|
1207
|
+
safely(() => callback.handleLLMError(toError(error, privacyMode()), runId));
|
|
1069
1208
|
throw error;
|
|
1070
1209
|
}
|
|
1071
1210
|
},
|
|
@@ -1086,11 +1225,11 @@ const createPostHogMiddleware = (options) => {
|
|
|
1086
1225
|
safely(() => callback.handleToolStart(serializedTool, stringify(request.toolCall.args), runId, parentRunId, void 0, void 0, toolName));
|
|
1087
1226
|
try {
|
|
1088
1227
|
const result = await handler(request);
|
|
1089
|
-
if (ToolMessage.isInstance(result) && result.status === "error") safely(() => callback.handleToolError(
|
|
1228
|
+
if (ToolMessage.isInstance(result) && result.status === "error") safely(() => callback.handleToolError(toolMessageError(result, privacyMode()), runId, parentRunId));
|
|
1090
1229
|
else safely(() => callback.handleToolEnd(result, runId, parentRunId));
|
|
1091
1230
|
return result;
|
|
1092
1231
|
} catch (error) {
|
|
1093
|
-
safely(() => callback.handleToolError(toError(error), runId));
|
|
1232
|
+
safely(() => callback.handleToolError(toError(error, privacyMode()), runId));
|
|
1094
1233
|
throw error;
|
|
1095
1234
|
}
|
|
1096
1235
|
}
|