@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
package/dist/index.mjs
CHANGED
|
@@ -228,6 +228,10 @@ function redactBase64DataUrl(str, mediaType) {
|
|
|
228
228
|
const sanitize = (data, client) => isFullAiCaptureEnabled(client) ? data : redactor.redact(data);
|
|
229
229
|
const sanitizeVercel = (data, client) => sanitize(data, client);
|
|
230
230
|
//#endregion
|
|
231
|
+
//#region src/privacyMode.ts
|
|
232
|
+
/** Per-call settings can turn redaction on but never off. */
|
|
233
|
+
const isPrivacyModeEnabled = (client, privacyMode = false) => privacyMode === true || client?.privacyMode === true || client?.privacy_mode === true || client?.options?.privacyMode === true;
|
|
234
|
+
//#endregion
|
|
231
235
|
//#region src/utils.ts
|
|
232
236
|
const TOKEN_PROPERTY_KEYS = /* @__PURE__ */ new Set([
|
|
233
237
|
"$ai_input_tokens",
|
|
@@ -297,7 +301,6 @@ const getModelParams = (params, responseServiceTier) => {
|
|
|
297
301
|
if (responseServiceTier != null) modelParams.service_tier = responseServiceTier;
|
|
298
302
|
return modelParams;
|
|
299
303
|
};
|
|
300
|
-
const isPrivacyModeEnabled = (client, privacyMode) => Boolean(client.privacy_mode || privacyMode);
|
|
301
304
|
function toSafeString(input) {
|
|
302
305
|
if (input === void 0 || input === null) return "";
|
|
303
306
|
if (typeof input === "string") return input;
|
|
@@ -409,11 +412,12 @@ function sanitizeValues(obj) {
|
|
|
409
412
|
}
|
|
410
413
|
//#endregion
|
|
411
414
|
//#region package.json
|
|
412
|
-
var version = "8.16.
|
|
415
|
+
var version = "8.16.2";
|
|
413
416
|
//#endregion
|
|
414
417
|
//#region src/serializeError.ts
|
|
415
418
|
const DEFAULT_MAX_DEPTH = 3;
|
|
416
419
|
const MAX_STACK_LINES = 20;
|
|
420
|
+
const OMITTED_FIELD = "requestBodyValues";
|
|
417
421
|
function serializeError(value, depth = DEFAULT_MAX_DEPTH) {
|
|
418
422
|
if (depth < 0 || value === null || typeof value !== "object") return value;
|
|
419
423
|
if (value instanceof Error) {
|
|
@@ -422,16 +426,17 @@ function serializeError(value, depth = DEFAULT_MAX_DEPTH) {
|
|
|
422
426
|
message: value.message,
|
|
423
427
|
stack: truncateStack(value.stack)
|
|
424
428
|
};
|
|
425
|
-
for (const key of Object.keys(value)) out[key] = serializeError(value
|
|
429
|
+
for (const key of Object.keys(value)) if (key !== OMITTED_FIELD) out[key] = serializeError(Reflect.get(value, key), depth - 1);
|
|
426
430
|
if (value.cause !== void 0) out.cause = serializeError(value.cause, depth - 1);
|
|
427
431
|
return out;
|
|
428
432
|
}
|
|
429
433
|
if (Array.isArray(value)) return value.map((item) => serializeError(item, depth - 1));
|
|
430
434
|
return value;
|
|
431
435
|
}
|
|
436
|
+
const omitRequestBody = (key, value) => key === OMITTED_FIELD ? void 0 : value;
|
|
432
437
|
function stringifyError(error) {
|
|
433
438
|
try {
|
|
434
|
-
return JSON.stringify(sanitizeValues(serializeError(error)));
|
|
439
|
+
return JSON.stringify(sanitizeValues(serializeError(error)), omitRequestBody);
|
|
435
440
|
} catch {
|
|
436
441
|
if (error instanceof Error) return JSON.stringify({
|
|
437
442
|
name: error.name,
|
|
@@ -440,6 +445,105 @@ function stringifyError(error) {
|
|
|
440
445
|
return JSON.stringify({ message: String(error) });
|
|
441
446
|
}
|
|
442
447
|
}
|
|
448
|
+
const CLASS_NAME = /^[A-Za-z_$][A-Za-z0-9_$.]{0,127}$/;
|
|
449
|
+
const PROVIDER_CODE = /^[A-Za-z0-9_.:-]{1,64}$/;
|
|
450
|
+
const PARAM = /^[A-Za-z0-9_.[\]-]{1,128}$/;
|
|
451
|
+
const REQUEST_ID = /^[A-Za-z0-9_.:-]{1,128}$/;
|
|
452
|
+
const MAX_CAUSES = 3;
|
|
453
|
+
const readField = (value, key) => {
|
|
454
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") return;
|
|
455
|
+
try {
|
|
456
|
+
return Reflect.get(value, key);
|
|
457
|
+
} catch {
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
const matching = (value, grammar) => typeof value === "string" && grammar.test(value) ? value : void 0;
|
|
462
|
+
const firstMatching = (values, grammar) => {
|
|
463
|
+
for (const value of values) {
|
|
464
|
+
const match = matching(value, grammar);
|
|
465
|
+
if (match !== void 0) return match;
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
const className = (value) => {
|
|
469
|
+
if (!(value instanceof Error)) return "NonErrorThrown";
|
|
470
|
+
const name = readField(value, "name");
|
|
471
|
+
return firstMatching([
|
|
472
|
+
name === "Error" ? void 0 : name,
|
|
473
|
+
readField(readField(value, "constructor"), "name"),
|
|
474
|
+
name
|
|
475
|
+
], CLASS_NAME) ?? "Error";
|
|
476
|
+
};
|
|
477
|
+
const httpStatus = (error) => {
|
|
478
|
+
for (const key of ["status", "statusCode"]) {
|
|
479
|
+
const value = readField(error, key);
|
|
480
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599) return value;
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
const unwrapEnvelope = (body) => {
|
|
484
|
+
const inner = readField(body, "error");
|
|
485
|
+
return inner !== null && typeof inner === "object" ? inner : body;
|
|
486
|
+
};
|
|
487
|
+
const parsedResponseBody = (error) => {
|
|
488
|
+
const responseBody = readField(error, "responseBody");
|
|
489
|
+
if (typeof responseBody !== "string") return;
|
|
490
|
+
try {
|
|
491
|
+
return unwrapEnvelope(JSON.parse(responseBody));
|
|
492
|
+
} catch {
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
const causeNames = (error) => {
|
|
497
|
+
const names = [];
|
|
498
|
+
let cause = readField(error, "cause");
|
|
499
|
+
while (cause !== void 0 && cause !== null && names.length < MAX_CAUSES) {
|
|
500
|
+
names.push(className(cause));
|
|
501
|
+
cause = readField(cause, "cause");
|
|
502
|
+
}
|
|
503
|
+
return names;
|
|
504
|
+
};
|
|
505
|
+
const describeError = (error) => {
|
|
506
|
+
const sources = [
|
|
507
|
+
error,
|
|
508
|
+
unwrapEnvelope(readField(error, "error")),
|
|
509
|
+
parsedResponseBody(error)
|
|
510
|
+
];
|
|
511
|
+
const codes = /* @__PURE__ */ new Set();
|
|
512
|
+
for (const source of sources) for (const key of [
|
|
513
|
+
"code",
|
|
514
|
+
"type",
|
|
515
|
+
"status"
|
|
516
|
+
]) {
|
|
517
|
+
const code = matching(readField(source, key), PROVIDER_CODE);
|
|
518
|
+
if (code !== void 0) codes.add(code);
|
|
519
|
+
}
|
|
520
|
+
const status = httpStatus(error);
|
|
521
|
+
const param = firstMatching(sources.map((source) => readField(source, "param")), PARAM);
|
|
522
|
+
const requestId = firstMatching([readField(error, "requestID"), readField(error, "request_id")], REQUEST_ID);
|
|
523
|
+
const causes = causeNames(error);
|
|
524
|
+
let summary = className(error);
|
|
525
|
+
if (status !== void 0) summary += `: ${status}`;
|
|
526
|
+
for (const code of codes) summary += ` ${code}`;
|
|
527
|
+
if (param !== void 0) summary += ` param=${param}`;
|
|
528
|
+
if (requestId !== void 0) summary += ` request_id=${requestId}`;
|
|
529
|
+
if (causes.length > 0) summary += ` (caused by ${causes.join(", ")})`;
|
|
530
|
+
return summary;
|
|
531
|
+
};
|
|
532
|
+
/**
|
|
533
|
+
* Describes an error for `$ai_error` without its message, stack, or arbitrary fields, which
|
|
534
|
+
* routinely echo the prompt. Only structured fields that pass a strict grammar are kept.
|
|
535
|
+
* The format matches the Python SDK.
|
|
536
|
+
*/
|
|
537
|
+
function summarizeErrorForPrivacy(error) {
|
|
538
|
+
try {
|
|
539
|
+
return describeError(error);
|
|
540
|
+
} catch {
|
|
541
|
+
return error instanceof Error ? "Error" : "NonErrorThrown";
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
function formatAiError(error, privacyMode) {
|
|
545
|
+
return privacyMode ? summarizeErrorForPrivacy(error) : stringifyError(error);
|
|
546
|
+
}
|
|
443
547
|
function truncateStack(stack) {
|
|
444
548
|
if (!stack) return stack;
|
|
445
549
|
const lines = stack.split("\n");
|
|
@@ -447,6 +551,33 @@ function truncateStack(stack) {
|
|
|
447
551
|
return [...lines.slice(0, MAX_STACK_LINES), "... (truncated)"].join("\n");
|
|
448
552
|
}
|
|
449
553
|
//#endregion
|
|
554
|
+
//#region src/mcpCredentials.ts
|
|
555
|
+
const MCP_CREDENTIAL_FIELDS = ["headers", "authorization"];
|
|
556
|
+
const MCP_PROVIDER_TOOL_IDS = /* @__PURE__ */ new Set([
|
|
557
|
+
"openai.mcp",
|
|
558
|
+
"xai.mcp",
|
|
559
|
+
"google.mcp_server"
|
|
560
|
+
]);
|
|
561
|
+
const isMcpProviderTool = (tool) => (tool.type === "provider" || tool.type === "provider-defined") && typeof tool.id === "string" && MCP_PROVIDER_TOOL_IDS.has(tool.id);
|
|
562
|
+
const withoutMcpCredentials = (config) => {
|
|
563
|
+
const redacted = { ...config };
|
|
564
|
+
for (const field of MCP_CREDENTIAL_FIELDS) if (field in redacted) redacted[field] = "[REDACTED]";
|
|
565
|
+
return redacted;
|
|
566
|
+
};
|
|
567
|
+
/** Hides the credentials of a remote MCP tool definition; everything else is kept as sent. */
|
|
568
|
+
function redactMcpToolDefinition(tool) {
|
|
569
|
+
if (!isObject(tool)) return tool;
|
|
570
|
+
if (tool.type === "mcp") return withoutMcpCredentials(tool);
|
|
571
|
+
if (isMcpProviderTool(tool) && isObject(tool.args)) return {
|
|
572
|
+
...tool,
|
|
573
|
+
args: withoutMcpCredentials(tool.args)
|
|
574
|
+
};
|
|
575
|
+
return tool;
|
|
576
|
+
}
|
|
577
|
+
function redactMcpToolCredentials(tools) {
|
|
578
|
+
return Array.isArray(tools) ? tools.map(redactMcpToolDefinition) : tools;
|
|
579
|
+
}
|
|
580
|
+
//#endregion
|
|
450
581
|
//#region src/gatewayWarning.ts
|
|
451
582
|
const POSTHOG_AI_GATEWAY_HOSTS = [
|
|
452
583
|
"gateway.posthog.com",
|
|
@@ -509,13 +640,15 @@ const captureAiGeneration = async (client, options) => {
|
|
|
509
640
|
}
|
|
510
641
|
let exceptionId;
|
|
511
642
|
if (client.options?.enableExceptionAutocapture) {
|
|
512
|
-
|
|
513
|
-
|
|
643
|
+
if (!shouldRedact) {
|
|
644
|
+
exceptionId = uuidv7();
|
|
645
|
+
client.captureException(options.error, void 0, { $ai_trace_id: traceId }, exceptionId);
|
|
646
|
+
}
|
|
514
647
|
if (typeof options.error === "object") options.error.__posthog_previously_captured_error = true;
|
|
515
648
|
}
|
|
516
649
|
errorData = {
|
|
517
650
|
$ai_is_error: true,
|
|
518
|
-
$ai_error:
|
|
651
|
+
$ai_error: formatAiError(options.error, shouldRedact),
|
|
519
652
|
$exception_event_id: exceptionId
|
|
520
653
|
};
|
|
521
654
|
}
|
|
@@ -556,7 +689,7 @@ const captureAiGeneration = async (client, options) => {
|
|
|
556
689
|
$ai_tokens_source: getTokensSource(options.properties),
|
|
557
690
|
...options.distinctId ? {} : { $process_person_profile: false },
|
|
558
691
|
...options.stopReason ? { $ai_stop_reason: options.stopReason } : {},
|
|
559
|
-
...options.tools ? { $ai_tools: options.tools } : {},
|
|
692
|
+
...options.tools ? { $ai_tools: redactMcpToolCredentials(options.tools) } : {},
|
|
560
693
|
...options.completionId ? { $ai_completion_id: options.completionId } : {},
|
|
561
694
|
...options.providerMetadata && Object.keys(options.providerMetadata).length > 0 ? { $ai_provider_metadata: options.providerMetadata } : {},
|
|
562
695
|
...errorData,
|
|
@@ -820,12 +953,13 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
820
953
|
$ai_framework_version: model.specificationVersion === "v3" ? "6" : "5"
|
|
821
954
|
}
|
|
822
955
|
};
|
|
956
|
+
const privacyMode = isPrivacyModeEnabled(phClient, mergedOptions.posthogPrivacyMode);
|
|
823
957
|
const baseOptions = {
|
|
824
958
|
distinctId: mergedOptions.posthogDistinctId,
|
|
825
959
|
traceId,
|
|
826
960
|
properties: mergedOptions.posthogProperties,
|
|
827
961
|
groups: mergedOptions.posthogGroups,
|
|
828
|
-
privacyMode
|
|
962
|
+
privacyMode,
|
|
829
963
|
modelOverride: mergedOptions.posthogModelOverride,
|
|
830
964
|
providerOverride: mergedOptions.posthogProviderOverride,
|
|
831
965
|
costOverride: mergedOptions.posthogCostOverride,
|
|
@@ -853,7 +987,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
853
987
|
const usageObj = result.usage;
|
|
854
988
|
const rawUsageData = {
|
|
855
989
|
usage: result.usage,
|
|
856
|
-
providerMetadata
|
|
990
|
+
...privacyMode ? {} : { providerMetadata }
|
|
857
991
|
};
|
|
858
992
|
if (result.response && typeof result.response === "object") {
|
|
859
993
|
const responseBody = result.response.body;
|
|
@@ -875,7 +1009,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
875
1009
|
...baseOptions,
|
|
876
1010
|
model: modelId,
|
|
877
1011
|
provider,
|
|
878
|
-
input:
|
|
1012
|
+
input: privacyMode ? "" : mapVercelPrompt(params.prompt, phClient),
|
|
879
1013
|
output: content,
|
|
880
1014
|
latency,
|
|
881
1015
|
baseURL,
|
|
@@ -892,7 +1026,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
892
1026
|
...baseOptions,
|
|
893
1027
|
model: modelId,
|
|
894
1028
|
provider: extractProvider(model),
|
|
895
|
-
input:
|
|
1029
|
+
input: privacyMode ? "" : mapVercelPrompt(params.prompt, phClient),
|
|
896
1030
|
output: [],
|
|
897
1031
|
latency: (Date.now() - startTime) / 1e3,
|
|
898
1032
|
baseURL,
|
|
@@ -1018,7 +1152,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
1018
1152
|
const finalUsage = {
|
|
1019
1153
|
...usage,
|
|
1020
1154
|
webSearchCount,
|
|
1021
|
-
rawUsage: {
|
|
1155
|
+
rawUsage: privacyMode ? { usage } : {
|
|
1022
1156
|
usage,
|
|
1023
1157
|
providerMetadata
|
|
1024
1158
|
}
|
|
@@ -1029,7 +1163,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
1029
1163
|
...baseOptions,
|
|
1030
1164
|
model: modelId,
|
|
1031
1165
|
provider,
|
|
1032
|
-
input:
|
|
1166
|
+
input: privacyMode ? "" : mapVercelPrompt(params.prompt, phClient),
|
|
1033
1167
|
output,
|
|
1034
1168
|
latency,
|
|
1035
1169
|
timeToFirstToken,
|
|
@@ -1079,7 +1213,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
1079
1213
|
...baseOptions,
|
|
1080
1214
|
model: modelId,
|
|
1081
1215
|
provider,
|
|
1082
|
-
input:
|
|
1216
|
+
input: privacyMode ? "" : mapVercelPrompt(params.prompt, phClient),
|
|
1083
1217
|
output: [],
|
|
1084
1218
|
latency: (Date.now() - startTime) / 1e3,
|
|
1085
1219
|
baseURL,
|