@posthog/ai 8.16.0 → 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 +154 -8
- package/dist/openai/index.cjs.map +1 -1
- package/dist/openai/index.mjs +154 -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/vercel/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;
|
|
@@ -405,11 +408,12 @@ function sanitizeValues(obj) {
|
|
|
405
408
|
}
|
|
406
409
|
//#endregion
|
|
407
410
|
//#region package.json
|
|
408
|
-
var version = "8.16.
|
|
411
|
+
var version = "8.16.2";
|
|
409
412
|
//#endregion
|
|
410
413
|
//#region src/serializeError.ts
|
|
411
414
|
const DEFAULT_MAX_DEPTH = 3;
|
|
412
415
|
const MAX_STACK_LINES = 20;
|
|
416
|
+
const OMITTED_FIELD = "requestBodyValues";
|
|
413
417
|
function serializeError(value, depth = DEFAULT_MAX_DEPTH) {
|
|
414
418
|
if (depth < 0 || value === null || typeof value !== "object") return value;
|
|
415
419
|
if (value instanceof Error) {
|
|
@@ -418,16 +422,17 @@ function serializeError(value, depth = DEFAULT_MAX_DEPTH) {
|
|
|
418
422
|
message: value.message,
|
|
419
423
|
stack: truncateStack(value.stack)
|
|
420
424
|
};
|
|
421
|
-
for (const key of Object.keys(value)) out[key] = serializeError(value
|
|
425
|
+
for (const key of Object.keys(value)) if (key !== OMITTED_FIELD) out[key] = serializeError(Reflect.get(value, key), depth - 1);
|
|
422
426
|
if (value.cause !== void 0) out.cause = serializeError(value.cause, depth - 1);
|
|
423
427
|
return out;
|
|
424
428
|
}
|
|
425
429
|
if (Array.isArray(value)) return value.map((item) => serializeError(item, depth - 1));
|
|
426
430
|
return value;
|
|
427
431
|
}
|
|
432
|
+
const omitRequestBody = (key, value) => key === OMITTED_FIELD ? void 0 : value;
|
|
428
433
|
function stringifyError(error) {
|
|
429
434
|
try {
|
|
430
|
-
return JSON.stringify(sanitizeValues(serializeError(error)));
|
|
435
|
+
return JSON.stringify(sanitizeValues(serializeError(error)), omitRequestBody);
|
|
431
436
|
} catch {
|
|
432
437
|
if (error instanceof Error) return JSON.stringify({
|
|
433
438
|
name: error.name,
|
|
@@ -436,6 +441,105 @@ function stringifyError(error) {
|
|
|
436
441
|
return JSON.stringify({ message: String(error) });
|
|
437
442
|
}
|
|
438
443
|
}
|
|
444
|
+
const CLASS_NAME = /^[A-Za-z_$][A-Za-z0-9_$.]{0,127}$/;
|
|
445
|
+
const PROVIDER_CODE = /^[A-Za-z0-9_.:-]{1,64}$/;
|
|
446
|
+
const PARAM = /^[A-Za-z0-9_.[\]-]{1,128}$/;
|
|
447
|
+
const REQUEST_ID = /^[A-Za-z0-9_.:-]{1,128}$/;
|
|
448
|
+
const MAX_CAUSES = 3;
|
|
449
|
+
const readField = (value, key) => {
|
|
450
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") return;
|
|
451
|
+
try {
|
|
452
|
+
return Reflect.get(value, key);
|
|
453
|
+
} catch {
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
const matching = (value, grammar) => typeof value === "string" && grammar.test(value) ? value : void 0;
|
|
458
|
+
const firstMatching = (values, grammar) => {
|
|
459
|
+
for (const value of values) {
|
|
460
|
+
const match = matching(value, grammar);
|
|
461
|
+
if (match !== void 0) return match;
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
const className = (value) => {
|
|
465
|
+
if (!(value instanceof Error)) return "NonErrorThrown";
|
|
466
|
+
const name = readField(value, "name");
|
|
467
|
+
return firstMatching([
|
|
468
|
+
name === "Error" ? void 0 : name,
|
|
469
|
+
readField(readField(value, "constructor"), "name"),
|
|
470
|
+
name
|
|
471
|
+
], CLASS_NAME) ?? "Error";
|
|
472
|
+
};
|
|
473
|
+
const httpStatus = (error) => {
|
|
474
|
+
for (const key of ["status", "statusCode"]) {
|
|
475
|
+
const value = readField(error, key);
|
|
476
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599) return value;
|
|
477
|
+
}
|
|
478
|
+
};
|
|
479
|
+
const unwrapEnvelope = (body) => {
|
|
480
|
+
const inner = readField(body, "error");
|
|
481
|
+
return inner !== null && typeof inner === "object" ? inner : body;
|
|
482
|
+
};
|
|
483
|
+
const parsedResponseBody = (error) => {
|
|
484
|
+
const responseBody = readField(error, "responseBody");
|
|
485
|
+
if (typeof responseBody !== "string") return;
|
|
486
|
+
try {
|
|
487
|
+
return unwrapEnvelope(JSON.parse(responseBody));
|
|
488
|
+
} catch {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
const causeNames = (error) => {
|
|
493
|
+
const names = [];
|
|
494
|
+
let cause = readField(error, "cause");
|
|
495
|
+
while (cause !== void 0 && cause !== null && names.length < MAX_CAUSES) {
|
|
496
|
+
names.push(className(cause));
|
|
497
|
+
cause = readField(cause, "cause");
|
|
498
|
+
}
|
|
499
|
+
return names;
|
|
500
|
+
};
|
|
501
|
+
const describeError = (error) => {
|
|
502
|
+
const sources = [
|
|
503
|
+
error,
|
|
504
|
+
unwrapEnvelope(readField(error, "error")),
|
|
505
|
+
parsedResponseBody(error)
|
|
506
|
+
];
|
|
507
|
+
const codes = /* @__PURE__ */ new Set();
|
|
508
|
+
for (const source of sources) for (const key of [
|
|
509
|
+
"code",
|
|
510
|
+
"type",
|
|
511
|
+
"status"
|
|
512
|
+
]) {
|
|
513
|
+
const code = matching(readField(source, key), PROVIDER_CODE);
|
|
514
|
+
if (code !== void 0) codes.add(code);
|
|
515
|
+
}
|
|
516
|
+
const status = httpStatus(error);
|
|
517
|
+
const param = firstMatching(sources.map((source) => readField(source, "param")), PARAM);
|
|
518
|
+
const requestId = firstMatching([readField(error, "requestID"), readField(error, "request_id")], REQUEST_ID);
|
|
519
|
+
const causes = causeNames(error);
|
|
520
|
+
let summary = className(error);
|
|
521
|
+
if (status !== void 0) summary += `: ${status}`;
|
|
522
|
+
for (const code of codes) summary += ` ${code}`;
|
|
523
|
+
if (param !== void 0) summary += ` param=${param}`;
|
|
524
|
+
if (requestId !== void 0) summary += ` request_id=${requestId}`;
|
|
525
|
+
if (causes.length > 0) summary += ` (caused by ${causes.join(", ")})`;
|
|
526
|
+
return summary;
|
|
527
|
+
};
|
|
528
|
+
/**
|
|
529
|
+
* Describes an error for `$ai_error` without its message, stack, or arbitrary fields, which
|
|
530
|
+
* routinely echo the prompt. Only structured fields that pass a strict grammar are kept.
|
|
531
|
+
* The format matches the Python SDK.
|
|
532
|
+
*/
|
|
533
|
+
function summarizeErrorForPrivacy(error) {
|
|
534
|
+
try {
|
|
535
|
+
return describeError(error);
|
|
536
|
+
} catch {
|
|
537
|
+
return error instanceof Error ? "Error" : "NonErrorThrown";
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
function formatAiError(error, privacyMode) {
|
|
541
|
+
return privacyMode ? summarizeErrorForPrivacy(error) : stringifyError(error);
|
|
542
|
+
}
|
|
439
543
|
function truncateStack(stack) {
|
|
440
544
|
if (!stack) return stack;
|
|
441
545
|
const lines = stack.split("\n");
|
|
@@ -443,6 +547,33 @@ function truncateStack(stack) {
|
|
|
443
547
|
return [...lines.slice(0, MAX_STACK_LINES), "... (truncated)"].join("\n");
|
|
444
548
|
}
|
|
445
549
|
//#endregion
|
|
550
|
+
//#region src/mcpCredentials.ts
|
|
551
|
+
const MCP_CREDENTIAL_FIELDS = ["headers", "authorization"];
|
|
552
|
+
const MCP_PROVIDER_TOOL_IDS = /* @__PURE__ */ new Set([
|
|
553
|
+
"openai.mcp",
|
|
554
|
+
"xai.mcp",
|
|
555
|
+
"google.mcp_server"
|
|
556
|
+
]);
|
|
557
|
+
const isMcpProviderTool = (tool) => (tool.type === "provider" || tool.type === "provider-defined") && typeof tool.id === "string" && MCP_PROVIDER_TOOL_IDS.has(tool.id);
|
|
558
|
+
const withoutMcpCredentials = (config) => {
|
|
559
|
+
const redacted = { ...config };
|
|
560
|
+
for (const field of MCP_CREDENTIAL_FIELDS) if (field in redacted) redacted[field] = "[REDACTED]";
|
|
561
|
+
return redacted;
|
|
562
|
+
};
|
|
563
|
+
/** Hides the credentials of a remote MCP tool definition; everything else is kept as sent. */
|
|
564
|
+
function redactMcpToolDefinition(tool) {
|
|
565
|
+
if (!isObject(tool)) return tool;
|
|
566
|
+
if (tool.type === "mcp") return withoutMcpCredentials(tool);
|
|
567
|
+
if (isMcpProviderTool(tool) && isObject(tool.args)) return {
|
|
568
|
+
...tool,
|
|
569
|
+
args: withoutMcpCredentials(tool.args)
|
|
570
|
+
};
|
|
571
|
+
return tool;
|
|
572
|
+
}
|
|
573
|
+
function redactMcpToolCredentials(tools) {
|
|
574
|
+
return Array.isArray(tools) ? tools.map(redactMcpToolDefinition) : tools;
|
|
575
|
+
}
|
|
576
|
+
//#endregion
|
|
446
577
|
//#region src/gatewayWarning.ts
|
|
447
578
|
const POSTHOG_AI_GATEWAY_HOSTS = [
|
|
448
579
|
"gateway.posthog.com",
|
|
@@ -505,13 +636,15 @@ const captureAiGeneration = async (client, options) => {
|
|
|
505
636
|
}
|
|
506
637
|
let exceptionId;
|
|
507
638
|
if (client.options?.enableExceptionAutocapture) {
|
|
508
|
-
|
|
509
|
-
|
|
639
|
+
if (!shouldRedact) {
|
|
640
|
+
exceptionId = (0, _posthog_core.uuidv7)();
|
|
641
|
+
client.captureException(options.error, void 0, { $ai_trace_id: traceId }, exceptionId);
|
|
642
|
+
}
|
|
510
643
|
if (typeof options.error === "object") options.error.__posthog_previously_captured_error = true;
|
|
511
644
|
}
|
|
512
645
|
errorData = {
|
|
513
646
|
$ai_is_error: true,
|
|
514
|
-
$ai_error:
|
|
647
|
+
$ai_error: formatAiError(options.error, shouldRedact),
|
|
515
648
|
$exception_event_id: exceptionId
|
|
516
649
|
};
|
|
517
650
|
}
|
|
@@ -552,7 +685,7 @@ const captureAiGeneration = async (client, options) => {
|
|
|
552
685
|
$ai_tokens_source: getTokensSource(options.properties),
|
|
553
686
|
...options.distinctId ? {} : { $process_person_profile: false },
|
|
554
687
|
...options.stopReason ? { $ai_stop_reason: options.stopReason } : {},
|
|
555
|
-
...options.tools ? { $ai_tools: options.tools } : {},
|
|
688
|
+
...options.tools ? { $ai_tools: redactMcpToolCredentials(options.tools) } : {},
|
|
556
689
|
...options.completionId ? { $ai_completion_id: options.completionId } : {},
|
|
557
690
|
...options.providerMetadata && Object.keys(options.providerMetadata).length > 0 ? { $ai_provider_metadata: options.providerMetadata } : {},
|
|
558
691
|
...errorData,
|
|
@@ -816,12 +949,13 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
816
949
|
$ai_framework_version: model.specificationVersion === "v3" ? "6" : "5"
|
|
817
950
|
}
|
|
818
951
|
};
|
|
952
|
+
const privacyMode = isPrivacyModeEnabled(phClient, mergedOptions.posthogPrivacyMode);
|
|
819
953
|
const baseOptions = {
|
|
820
954
|
distinctId: mergedOptions.posthogDistinctId,
|
|
821
955
|
traceId,
|
|
822
956
|
properties: mergedOptions.posthogProperties,
|
|
823
957
|
groups: mergedOptions.posthogGroups,
|
|
824
|
-
privacyMode
|
|
958
|
+
privacyMode,
|
|
825
959
|
modelOverride: mergedOptions.posthogModelOverride,
|
|
826
960
|
providerOverride: mergedOptions.posthogProviderOverride,
|
|
827
961
|
costOverride: mergedOptions.posthogCostOverride,
|
|
@@ -849,7 +983,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
849
983
|
const usageObj = result.usage;
|
|
850
984
|
const rawUsageData = {
|
|
851
985
|
usage: result.usage,
|
|
852
|
-
providerMetadata
|
|
986
|
+
...privacyMode ? {} : { providerMetadata }
|
|
853
987
|
};
|
|
854
988
|
if (result.response && typeof result.response === "object") {
|
|
855
989
|
const responseBody = result.response.body;
|
|
@@ -871,7 +1005,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
871
1005
|
...baseOptions,
|
|
872
1006
|
model: modelId,
|
|
873
1007
|
provider,
|
|
874
|
-
input:
|
|
1008
|
+
input: privacyMode ? "" : mapVercelPrompt(params.prompt, phClient),
|
|
875
1009
|
output: content,
|
|
876
1010
|
latency,
|
|
877
1011
|
baseURL,
|
|
@@ -888,7 +1022,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
888
1022
|
...baseOptions,
|
|
889
1023
|
model: modelId,
|
|
890
1024
|
provider: extractProvider(model),
|
|
891
|
-
input:
|
|
1025
|
+
input: privacyMode ? "" : mapVercelPrompt(params.prompt, phClient),
|
|
892
1026
|
output: [],
|
|
893
1027
|
latency: (Date.now() - startTime) / 1e3,
|
|
894
1028
|
baseURL,
|
|
@@ -1014,7 +1148,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
1014
1148
|
const finalUsage = {
|
|
1015
1149
|
...usage,
|
|
1016
1150
|
webSearchCount,
|
|
1017
|
-
rawUsage: {
|
|
1151
|
+
rawUsage: privacyMode ? { usage } : {
|
|
1018
1152
|
usage,
|
|
1019
1153
|
providerMetadata
|
|
1020
1154
|
}
|
|
@@ -1025,7 +1159,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
1025
1159
|
...baseOptions,
|
|
1026
1160
|
model: modelId,
|
|
1027
1161
|
provider,
|
|
1028
|
-
input:
|
|
1162
|
+
input: privacyMode ? "" : mapVercelPrompt(params.prompt, phClient),
|
|
1029
1163
|
output,
|
|
1030
1164
|
latency,
|
|
1031
1165
|
timeToFirstToken,
|
|
@@ -1075,7 +1209,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
|
|
|
1075
1209
|
...baseOptions,
|
|
1076
1210
|
model: modelId,
|
|
1077
1211
|
provider,
|
|
1078
|
-
input:
|
|
1212
|
+
input: privacyMode ? "" : mapVercelPrompt(params.prompt, phClient),
|
|
1079
1213
|
output: [],
|
|
1080
1214
|
latency: (Date.now() - startTime) / 1e3,
|
|
1081
1215
|
baseURL,
|