@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/openai/index.mjs
CHANGED
|
@@ -228,6 +228,10 @@ const sanitize = (data, client) => isFullAiCaptureEnabled(client) ? data : redac
|
|
|
228
228
|
const sanitizeOpenAI = (data, client) => sanitize(data, client);
|
|
229
229
|
const sanitizeOpenAIResponse = (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",
|
|
@@ -374,7 +378,6 @@ const formatResponseOpenAI = (response) => {
|
|
|
374
378
|
}
|
|
375
379
|
return output;
|
|
376
380
|
};
|
|
377
|
-
const isPrivacyModeEnabled = (client, privacyMode) => Boolean(client.privacy_mode || privacyMode);
|
|
378
381
|
const withPrivacyMode = (client, privacyMode, input) => {
|
|
379
382
|
return isPrivacyModeEnabled(client, privacyMode) ? null : input;
|
|
380
383
|
};
|
|
@@ -545,11 +548,12 @@ function formatOpenAIResponsesInput(input, instructions) {
|
|
|
545
548
|
}
|
|
546
549
|
//#endregion
|
|
547
550
|
//#region package.json
|
|
548
|
-
var version = "8.16.
|
|
551
|
+
var version = "8.16.2";
|
|
549
552
|
//#endregion
|
|
550
553
|
//#region src/serializeError.ts
|
|
551
554
|
const DEFAULT_MAX_DEPTH = 3;
|
|
552
555
|
const MAX_STACK_LINES = 20;
|
|
556
|
+
const OMITTED_FIELD = "requestBodyValues";
|
|
553
557
|
function serializeError(value, depth = DEFAULT_MAX_DEPTH) {
|
|
554
558
|
if (depth < 0 || value === null || typeof value !== "object") return value;
|
|
555
559
|
if (value instanceof Error) {
|
|
@@ -558,16 +562,17 @@ function serializeError(value, depth = DEFAULT_MAX_DEPTH) {
|
|
|
558
562
|
message: value.message,
|
|
559
563
|
stack: truncateStack(value.stack)
|
|
560
564
|
};
|
|
561
|
-
for (const key of Object.keys(value)) out[key] = serializeError(value
|
|
565
|
+
for (const key of Object.keys(value)) if (key !== OMITTED_FIELD) out[key] = serializeError(Reflect.get(value, key), depth - 1);
|
|
562
566
|
if (value.cause !== void 0) out.cause = serializeError(value.cause, depth - 1);
|
|
563
567
|
return out;
|
|
564
568
|
}
|
|
565
569
|
if (Array.isArray(value)) return value.map((item) => serializeError(item, depth - 1));
|
|
566
570
|
return value;
|
|
567
571
|
}
|
|
572
|
+
const omitRequestBody = (key, value) => key === OMITTED_FIELD ? void 0 : value;
|
|
568
573
|
function stringifyError(error) {
|
|
569
574
|
try {
|
|
570
|
-
return JSON.stringify(sanitizeValues(serializeError(error)));
|
|
575
|
+
return JSON.stringify(sanitizeValues(serializeError(error)), omitRequestBody);
|
|
571
576
|
} catch {
|
|
572
577
|
if (error instanceof Error) return JSON.stringify({
|
|
573
578
|
name: error.name,
|
|
@@ -576,6 +581,105 @@ function stringifyError(error) {
|
|
|
576
581
|
return JSON.stringify({ message: String(error) });
|
|
577
582
|
}
|
|
578
583
|
}
|
|
584
|
+
const CLASS_NAME = /^[A-Za-z_$][A-Za-z0-9_$.]{0,127}$/;
|
|
585
|
+
const PROVIDER_CODE = /^[A-Za-z0-9_.:-]{1,64}$/;
|
|
586
|
+
const PARAM = /^[A-Za-z0-9_.[\]-]{1,128}$/;
|
|
587
|
+
const REQUEST_ID = /^[A-Za-z0-9_.:-]{1,128}$/;
|
|
588
|
+
const MAX_CAUSES = 3;
|
|
589
|
+
const readField = (value, key) => {
|
|
590
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") return;
|
|
591
|
+
try {
|
|
592
|
+
return Reflect.get(value, key);
|
|
593
|
+
} catch {
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
const matching = (value, grammar) => typeof value === "string" && grammar.test(value) ? value : void 0;
|
|
598
|
+
const firstMatching = (values, grammar) => {
|
|
599
|
+
for (const value of values) {
|
|
600
|
+
const match = matching(value, grammar);
|
|
601
|
+
if (match !== void 0) return match;
|
|
602
|
+
}
|
|
603
|
+
};
|
|
604
|
+
const className = (value) => {
|
|
605
|
+
if (!(value instanceof Error)) return "NonErrorThrown";
|
|
606
|
+
const name = readField(value, "name");
|
|
607
|
+
return firstMatching([
|
|
608
|
+
name === "Error" ? void 0 : name,
|
|
609
|
+
readField(readField(value, "constructor"), "name"),
|
|
610
|
+
name
|
|
611
|
+
], CLASS_NAME) ?? "Error";
|
|
612
|
+
};
|
|
613
|
+
const httpStatus = (error) => {
|
|
614
|
+
for (const key of ["status", "statusCode"]) {
|
|
615
|
+
const value = readField(error, key);
|
|
616
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599) return value;
|
|
617
|
+
}
|
|
618
|
+
};
|
|
619
|
+
const unwrapEnvelope = (body) => {
|
|
620
|
+
const inner = readField(body, "error");
|
|
621
|
+
return inner !== null && typeof inner === "object" ? inner : body;
|
|
622
|
+
};
|
|
623
|
+
const parsedResponseBody = (error) => {
|
|
624
|
+
const responseBody = readField(error, "responseBody");
|
|
625
|
+
if (typeof responseBody !== "string") return;
|
|
626
|
+
try {
|
|
627
|
+
return unwrapEnvelope(JSON.parse(responseBody));
|
|
628
|
+
} catch {
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
const causeNames = (error) => {
|
|
633
|
+
const names = [];
|
|
634
|
+
let cause = readField(error, "cause");
|
|
635
|
+
while (cause !== void 0 && cause !== null && names.length < MAX_CAUSES) {
|
|
636
|
+
names.push(className(cause));
|
|
637
|
+
cause = readField(cause, "cause");
|
|
638
|
+
}
|
|
639
|
+
return names;
|
|
640
|
+
};
|
|
641
|
+
const describeError = (error) => {
|
|
642
|
+
const sources = [
|
|
643
|
+
error,
|
|
644
|
+
unwrapEnvelope(readField(error, "error")),
|
|
645
|
+
parsedResponseBody(error)
|
|
646
|
+
];
|
|
647
|
+
const codes = /* @__PURE__ */ new Set();
|
|
648
|
+
for (const source of sources) for (const key of [
|
|
649
|
+
"code",
|
|
650
|
+
"type",
|
|
651
|
+
"status"
|
|
652
|
+
]) {
|
|
653
|
+
const code = matching(readField(source, key), PROVIDER_CODE);
|
|
654
|
+
if (code !== void 0) codes.add(code);
|
|
655
|
+
}
|
|
656
|
+
const status = httpStatus(error);
|
|
657
|
+
const param = firstMatching(sources.map((source) => readField(source, "param")), PARAM);
|
|
658
|
+
const requestId = firstMatching([readField(error, "requestID"), readField(error, "request_id")], REQUEST_ID);
|
|
659
|
+
const causes = causeNames(error);
|
|
660
|
+
let summary = className(error);
|
|
661
|
+
if (status !== void 0) summary += `: ${status}`;
|
|
662
|
+
for (const code of codes) summary += ` ${code}`;
|
|
663
|
+
if (param !== void 0) summary += ` param=${param}`;
|
|
664
|
+
if (requestId !== void 0) summary += ` request_id=${requestId}`;
|
|
665
|
+
if (causes.length > 0) summary += ` (caused by ${causes.join(", ")})`;
|
|
666
|
+
return summary;
|
|
667
|
+
};
|
|
668
|
+
/**
|
|
669
|
+
* Describes an error for `$ai_error` without its message, stack, or arbitrary fields, which
|
|
670
|
+
* routinely echo the prompt. Only structured fields that pass a strict grammar are kept.
|
|
671
|
+
* The format matches the Python SDK.
|
|
672
|
+
*/
|
|
673
|
+
function summarizeErrorForPrivacy(error) {
|
|
674
|
+
try {
|
|
675
|
+
return describeError(error);
|
|
676
|
+
} catch {
|
|
677
|
+
return error instanceof Error ? "Error" : "NonErrorThrown";
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
function formatAiError(error, privacyMode) {
|
|
681
|
+
return privacyMode ? summarizeErrorForPrivacy(error) : stringifyError(error);
|
|
682
|
+
}
|
|
579
683
|
function truncateStack(stack) {
|
|
580
684
|
if (!stack) return stack;
|
|
581
685
|
const lines = stack.split("\n");
|
|
@@ -583,6 +687,33 @@ function truncateStack(stack) {
|
|
|
583
687
|
return [...lines.slice(0, MAX_STACK_LINES), "... (truncated)"].join("\n");
|
|
584
688
|
}
|
|
585
689
|
//#endregion
|
|
690
|
+
//#region src/mcpCredentials.ts
|
|
691
|
+
const MCP_CREDENTIAL_FIELDS = ["headers", "authorization"];
|
|
692
|
+
const MCP_PROVIDER_TOOL_IDS = /* @__PURE__ */ new Set([
|
|
693
|
+
"openai.mcp",
|
|
694
|
+
"xai.mcp",
|
|
695
|
+
"google.mcp_server"
|
|
696
|
+
]);
|
|
697
|
+
const isMcpProviderTool = (tool) => (tool.type === "provider" || tool.type === "provider-defined") && typeof tool.id === "string" && MCP_PROVIDER_TOOL_IDS.has(tool.id);
|
|
698
|
+
const withoutMcpCredentials = (config) => {
|
|
699
|
+
const redacted = { ...config };
|
|
700
|
+
for (const field of MCP_CREDENTIAL_FIELDS) if (field in redacted) redacted[field] = "[REDACTED]";
|
|
701
|
+
return redacted;
|
|
702
|
+
};
|
|
703
|
+
/** Hides the credentials of a remote MCP tool definition; everything else is kept as sent. */
|
|
704
|
+
function redactMcpToolDefinition(tool) {
|
|
705
|
+
if (!isObject(tool)) return tool;
|
|
706
|
+
if (tool.type === "mcp") return withoutMcpCredentials(tool);
|
|
707
|
+
if (isMcpProviderTool(tool) && isObject(tool.args)) return {
|
|
708
|
+
...tool,
|
|
709
|
+
args: withoutMcpCredentials(tool.args)
|
|
710
|
+
};
|
|
711
|
+
return tool;
|
|
712
|
+
}
|
|
713
|
+
function redactMcpToolCredentials(tools) {
|
|
714
|
+
return Array.isArray(tools) ? tools.map(redactMcpToolDefinition) : tools;
|
|
715
|
+
}
|
|
716
|
+
//#endregion
|
|
586
717
|
//#region src/gatewayWarning.ts
|
|
587
718
|
const POSTHOG_AI_GATEWAY_HOSTS = [
|
|
588
719
|
"gateway.posthog.com",
|
|
@@ -645,13 +776,15 @@ const captureAiGeneration$1 = async (client, options) => {
|
|
|
645
776
|
}
|
|
646
777
|
let exceptionId;
|
|
647
778
|
if (client.options?.enableExceptionAutocapture) {
|
|
648
|
-
|
|
649
|
-
|
|
779
|
+
if (!shouldRedact) {
|
|
780
|
+
exceptionId = uuidv7();
|
|
781
|
+
client.captureException(options.error, void 0, { $ai_trace_id: traceId }, exceptionId);
|
|
782
|
+
}
|
|
650
783
|
if (typeof options.error === "object") options.error.__posthog_previously_captured_error = true;
|
|
651
784
|
}
|
|
652
785
|
errorData = {
|
|
653
786
|
$ai_is_error: true,
|
|
654
|
-
$ai_error:
|
|
787
|
+
$ai_error: formatAiError(options.error, shouldRedact),
|
|
655
788
|
$exception_event_id: exceptionId
|
|
656
789
|
};
|
|
657
790
|
}
|
|
@@ -692,7 +825,7 @@ const captureAiGeneration$1 = async (client, options) => {
|
|
|
692
825
|
$ai_tokens_source: getTokensSource(options.properties),
|
|
693
826
|
...options.distinctId ? {} : { $process_person_profile: false },
|
|
694
827
|
...options.stopReason ? { $ai_stop_reason: options.stopReason } : {},
|
|
695
|
-
...options.tools ? { $ai_tools: options.tools } : {},
|
|
828
|
+
...options.tools ? { $ai_tools: redactMcpToolCredentials(options.tools) } : {},
|
|
696
829
|
...options.completionId ? { $ai_completion_id: options.completionId } : {},
|
|
697
830
|
...options.providerMetadata && Object.keys(options.providerMetadata).length > 0 ? { $ai_provider_metadata: options.providerMetadata } : {},
|
|
698
831
|
...errorData,
|