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