@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/openai/index.cjs
CHANGED
|
@@ -232,6 +232,10 @@ const sanitize = (data, client) => isFullAiCaptureEnabled(client) ? data : redac
|
|
|
232
232
|
const sanitizeOpenAI = (data, client) => sanitize(data, client);
|
|
233
233
|
const sanitizeOpenAIResponse = (data, client) => sanitize(data, client);
|
|
234
234
|
//#endregion
|
|
235
|
+
//#region src/privacyMode.ts
|
|
236
|
+
/** Per-call settings can turn redaction on but never off. */
|
|
237
|
+
const isPrivacyModeEnabled = (client, privacyMode = false) => privacyMode === true || client?.privacyMode === true || client?.privacy_mode === true || client?.options?.privacyMode === true;
|
|
238
|
+
//#endregion
|
|
235
239
|
//#region src/utils.ts
|
|
236
240
|
const TOKEN_PROPERTY_KEYS = /* @__PURE__ */ new Set([
|
|
237
241
|
"$ai_input_tokens",
|
|
@@ -311,6 +315,10 @@ const formatResponseOpenAI = (response) => {
|
|
|
311
315
|
type: "text",
|
|
312
316
|
text: choice.message.content
|
|
313
317
|
});
|
|
318
|
+
if (choice.message.refusal) content.push({
|
|
319
|
+
type: "refusal",
|
|
320
|
+
refusal: choice.message.refusal
|
|
321
|
+
});
|
|
314
322
|
if (choice.message.tool_calls) for (const toolCall of choice.message.tool_calls) {
|
|
315
323
|
const call = toolCall.type === "custom" ? toolCall.custom : toolCall.function;
|
|
316
324
|
if (!call) continue;
|
|
@@ -374,7 +382,6 @@ const formatResponseOpenAI = (response) => {
|
|
|
374
382
|
}
|
|
375
383
|
return output;
|
|
376
384
|
};
|
|
377
|
-
const isPrivacyModeEnabled = (client, privacyMode) => Boolean(client.privacy_mode || privacyMode);
|
|
378
385
|
const withPrivacyMode = (client, privacyMode, input) => {
|
|
379
386
|
return isPrivacyModeEnabled(client, privacyMode) ? null : input;
|
|
380
387
|
};
|
|
@@ -545,11 +552,12 @@ function formatOpenAIResponsesInput(input, instructions) {
|
|
|
545
552
|
}
|
|
546
553
|
//#endregion
|
|
547
554
|
//#region package.json
|
|
548
|
-
var version = "8.16.
|
|
555
|
+
var version = "8.16.2";
|
|
549
556
|
//#endregion
|
|
550
557
|
//#region src/serializeError.ts
|
|
551
558
|
const DEFAULT_MAX_DEPTH = 3;
|
|
552
559
|
const MAX_STACK_LINES = 20;
|
|
560
|
+
const OMITTED_FIELD = "requestBodyValues";
|
|
553
561
|
function serializeError(value, depth = DEFAULT_MAX_DEPTH) {
|
|
554
562
|
if (depth < 0 || value === null || typeof value !== "object") return value;
|
|
555
563
|
if (value instanceof Error) {
|
|
@@ -558,16 +566,17 @@ function serializeError(value, depth = DEFAULT_MAX_DEPTH) {
|
|
|
558
566
|
message: value.message,
|
|
559
567
|
stack: truncateStack(value.stack)
|
|
560
568
|
};
|
|
561
|
-
for (const key of Object.keys(value)) out[key] = serializeError(value
|
|
569
|
+
for (const key of Object.keys(value)) if (key !== OMITTED_FIELD) out[key] = serializeError(Reflect.get(value, key), depth - 1);
|
|
562
570
|
if (value.cause !== void 0) out.cause = serializeError(value.cause, depth - 1);
|
|
563
571
|
return out;
|
|
564
572
|
}
|
|
565
573
|
if (Array.isArray(value)) return value.map((item) => serializeError(item, depth - 1));
|
|
566
574
|
return value;
|
|
567
575
|
}
|
|
576
|
+
const omitRequestBody = (key, value) => key === OMITTED_FIELD ? void 0 : value;
|
|
568
577
|
function stringifyError(error) {
|
|
569
578
|
try {
|
|
570
|
-
return JSON.stringify(sanitizeValues(serializeError(error)));
|
|
579
|
+
return JSON.stringify(sanitizeValues(serializeError(error)), omitRequestBody);
|
|
571
580
|
} catch {
|
|
572
581
|
if (error instanceof Error) return JSON.stringify({
|
|
573
582
|
name: error.name,
|
|
@@ -576,6 +585,105 @@ function stringifyError(error) {
|
|
|
576
585
|
return JSON.stringify({ message: String(error) });
|
|
577
586
|
}
|
|
578
587
|
}
|
|
588
|
+
const CLASS_NAME = /^[A-Za-z_$][A-Za-z0-9_$.]{0,127}$/;
|
|
589
|
+
const PROVIDER_CODE = /^[A-Za-z0-9_.:-]{1,64}$/;
|
|
590
|
+
const PARAM = /^[A-Za-z0-9_.[\]-]{1,128}$/;
|
|
591
|
+
const REQUEST_ID = /^[A-Za-z0-9_.:-]{1,128}$/;
|
|
592
|
+
const MAX_CAUSES = 3;
|
|
593
|
+
const readField = (value, key) => {
|
|
594
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") return;
|
|
595
|
+
try {
|
|
596
|
+
return Reflect.get(value, key);
|
|
597
|
+
} catch {
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
};
|
|
601
|
+
const matching = (value, grammar) => typeof value === "string" && grammar.test(value) ? value : void 0;
|
|
602
|
+
const firstMatching = (values, grammar) => {
|
|
603
|
+
for (const value of values) {
|
|
604
|
+
const match = matching(value, grammar);
|
|
605
|
+
if (match !== void 0) return match;
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
const className = (value) => {
|
|
609
|
+
if (!(value instanceof Error)) return "NonErrorThrown";
|
|
610
|
+
const name = readField(value, "name");
|
|
611
|
+
return firstMatching([
|
|
612
|
+
name === "Error" ? void 0 : name,
|
|
613
|
+
readField(readField(value, "constructor"), "name"),
|
|
614
|
+
name
|
|
615
|
+
], CLASS_NAME) ?? "Error";
|
|
616
|
+
};
|
|
617
|
+
const httpStatus = (error) => {
|
|
618
|
+
for (const key of ["status", "statusCode"]) {
|
|
619
|
+
const value = readField(error, key);
|
|
620
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599) return value;
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
const unwrapEnvelope = (body) => {
|
|
624
|
+
const inner = readField(body, "error");
|
|
625
|
+
return inner !== null && typeof inner === "object" ? inner : body;
|
|
626
|
+
};
|
|
627
|
+
const parsedResponseBody = (error) => {
|
|
628
|
+
const responseBody = readField(error, "responseBody");
|
|
629
|
+
if (typeof responseBody !== "string") return;
|
|
630
|
+
try {
|
|
631
|
+
return unwrapEnvelope(JSON.parse(responseBody));
|
|
632
|
+
} catch {
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
const causeNames = (error) => {
|
|
637
|
+
const names = [];
|
|
638
|
+
let cause = readField(error, "cause");
|
|
639
|
+
while (cause !== void 0 && cause !== null && names.length < MAX_CAUSES) {
|
|
640
|
+
names.push(className(cause));
|
|
641
|
+
cause = readField(cause, "cause");
|
|
642
|
+
}
|
|
643
|
+
return names;
|
|
644
|
+
};
|
|
645
|
+
const describeError = (error) => {
|
|
646
|
+
const sources = [
|
|
647
|
+
error,
|
|
648
|
+
unwrapEnvelope(readField(error, "error")),
|
|
649
|
+
parsedResponseBody(error)
|
|
650
|
+
];
|
|
651
|
+
const codes = /* @__PURE__ */ new Set();
|
|
652
|
+
for (const source of sources) for (const key of [
|
|
653
|
+
"code",
|
|
654
|
+
"type",
|
|
655
|
+
"status"
|
|
656
|
+
]) {
|
|
657
|
+
const code = matching(readField(source, key), PROVIDER_CODE);
|
|
658
|
+
if (code !== void 0) codes.add(code);
|
|
659
|
+
}
|
|
660
|
+
const status = httpStatus(error);
|
|
661
|
+
const param = firstMatching(sources.map((source) => readField(source, "param")), PARAM);
|
|
662
|
+
const requestId = firstMatching([readField(error, "requestID"), readField(error, "request_id")], REQUEST_ID);
|
|
663
|
+
const causes = causeNames(error);
|
|
664
|
+
let summary = className(error);
|
|
665
|
+
if (status !== void 0) summary += `: ${status}`;
|
|
666
|
+
for (const code of codes) summary += ` ${code}`;
|
|
667
|
+
if (param !== void 0) summary += ` param=${param}`;
|
|
668
|
+
if (requestId !== void 0) summary += ` request_id=${requestId}`;
|
|
669
|
+
if (causes.length > 0) summary += ` (caused by ${causes.join(", ")})`;
|
|
670
|
+
return summary;
|
|
671
|
+
};
|
|
672
|
+
/**
|
|
673
|
+
* Describes an error for `$ai_error` without its message, stack, or arbitrary fields, which
|
|
674
|
+
* routinely echo the prompt. Only structured fields that pass a strict grammar are kept.
|
|
675
|
+
* The format matches the Python SDK.
|
|
676
|
+
*/
|
|
677
|
+
function summarizeErrorForPrivacy(error) {
|
|
678
|
+
try {
|
|
679
|
+
return describeError(error);
|
|
680
|
+
} catch {
|
|
681
|
+
return error instanceof Error ? "Error" : "NonErrorThrown";
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
function formatAiError(error, privacyMode) {
|
|
685
|
+
return privacyMode ? summarizeErrorForPrivacy(error) : stringifyError(error);
|
|
686
|
+
}
|
|
579
687
|
function truncateStack(stack) {
|
|
580
688
|
if (!stack) return stack;
|
|
581
689
|
const lines = stack.split("\n");
|
|
@@ -583,6 +691,33 @@ function truncateStack(stack) {
|
|
|
583
691
|
return [...lines.slice(0, MAX_STACK_LINES), "... (truncated)"].join("\n");
|
|
584
692
|
}
|
|
585
693
|
//#endregion
|
|
694
|
+
//#region src/mcpCredentials.ts
|
|
695
|
+
const MCP_CREDENTIAL_FIELDS = ["headers", "authorization"];
|
|
696
|
+
const MCP_PROVIDER_TOOL_IDS = /* @__PURE__ */ new Set([
|
|
697
|
+
"openai.mcp",
|
|
698
|
+
"xai.mcp",
|
|
699
|
+
"google.mcp_server"
|
|
700
|
+
]);
|
|
701
|
+
const isMcpProviderTool = (tool) => (tool.type === "provider" || tool.type === "provider-defined") && typeof tool.id === "string" && MCP_PROVIDER_TOOL_IDS.has(tool.id);
|
|
702
|
+
const withoutMcpCredentials = (config) => {
|
|
703
|
+
const redacted = { ...config };
|
|
704
|
+
for (const field of MCP_CREDENTIAL_FIELDS) if (field in redacted) redacted[field] = "[REDACTED]";
|
|
705
|
+
return redacted;
|
|
706
|
+
};
|
|
707
|
+
/** Hides the credentials of a remote MCP tool definition; everything else is kept as sent. */
|
|
708
|
+
function redactMcpToolDefinition(tool) {
|
|
709
|
+
if (!isObject(tool)) return tool;
|
|
710
|
+
if (tool.type === "mcp") return withoutMcpCredentials(tool);
|
|
711
|
+
if (isMcpProviderTool(tool) && isObject(tool.args)) return {
|
|
712
|
+
...tool,
|
|
713
|
+
args: withoutMcpCredentials(tool.args)
|
|
714
|
+
};
|
|
715
|
+
return tool;
|
|
716
|
+
}
|
|
717
|
+
function redactMcpToolCredentials(tools) {
|
|
718
|
+
return Array.isArray(tools) ? tools.map(redactMcpToolDefinition) : tools;
|
|
719
|
+
}
|
|
720
|
+
//#endregion
|
|
586
721
|
//#region src/gatewayWarning.ts
|
|
587
722
|
const POSTHOG_AI_GATEWAY_HOSTS = [
|
|
588
723
|
"gateway.posthog.com",
|
|
@@ -645,13 +780,15 @@ const captureAiGeneration$1 = async (client, options) => {
|
|
|
645
780
|
}
|
|
646
781
|
let exceptionId;
|
|
647
782
|
if (client.options?.enableExceptionAutocapture) {
|
|
648
|
-
|
|
649
|
-
|
|
783
|
+
if (!shouldRedact) {
|
|
784
|
+
exceptionId = (0, _posthog_core.uuidv7)();
|
|
785
|
+
client.captureException(options.error, void 0, { $ai_trace_id: traceId }, exceptionId);
|
|
786
|
+
}
|
|
650
787
|
if (typeof options.error === "object") options.error.__posthog_previously_captured_error = true;
|
|
651
788
|
}
|
|
652
789
|
errorData = {
|
|
653
790
|
$ai_is_error: true,
|
|
654
|
-
$ai_error:
|
|
791
|
+
$ai_error: formatAiError(options.error, shouldRedact),
|
|
655
792
|
$exception_event_id: exceptionId
|
|
656
793
|
};
|
|
657
794
|
}
|
|
@@ -692,7 +829,7 @@ const captureAiGeneration$1 = async (client, options) => {
|
|
|
692
829
|
$ai_tokens_source: getTokensSource(options.properties),
|
|
693
830
|
...options.distinctId ? {} : { $process_person_profile: false },
|
|
694
831
|
...options.stopReason ? { $ai_stop_reason: options.stopReason } : {},
|
|
695
|
-
...options.tools ? { $ai_tools: options.tools } : {},
|
|
832
|
+
...options.tools ? { $ai_tools: redactMcpToolCredentials(options.tools) } : {},
|
|
696
833
|
...options.completionId ? { $ai_completion_id: options.completionId } : {},
|
|
697
834
|
...options.providerMetadata && Object.keys(options.providerMetadata).length > 0 ? { $ai_provider_metadata: options.providerMetadata } : {},
|
|
698
835
|
...errorData,
|
|
@@ -1146,6 +1283,7 @@ function monitoredStreamTee(source, createStream) {
|
|
|
1146
1283
|
var OpenAIChatStreamAccumulator = class {
|
|
1147
1284
|
constructor() {
|
|
1148
1285
|
this.accumulatedContent = "";
|
|
1286
|
+
this.accumulatedRefusal = "";
|
|
1149
1287
|
this.usage = { webSearchCount: 0 };
|
|
1150
1288
|
this.toolCalls = /* @__PURE__ */ new Map();
|
|
1151
1289
|
}
|
|
@@ -1162,6 +1300,10 @@ var OpenAIChatStreamAccumulator = class {
|
|
|
1162
1300
|
this.firstTokenTime ??= receivedAt;
|
|
1163
1301
|
this.accumulatedContent += choice.delta.content;
|
|
1164
1302
|
}
|
|
1303
|
+
if (choice?.delta?.refusal) {
|
|
1304
|
+
this.firstTokenTime ??= receivedAt;
|
|
1305
|
+
this.accumulatedRefusal += choice.delta.refusal;
|
|
1306
|
+
}
|
|
1165
1307
|
if (Array.isArray(choice?.delta?.tool_calls)) {
|
|
1166
1308
|
this.firstTokenTime ??= receivedAt;
|
|
1167
1309
|
for (const toolCall of choice.delta.tool_calls) {
|
|
@@ -1193,6 +1335,10 @@ var OpenAIChatStreamAccumulator = class {
|
|
|
1193
1335
|
type: "text",
|
|
1194
1336
|
text: this.accumulatedContent
|
|
1195
1337
|
});
|
|
1338
|
+
if (this.accumulatedRefusal) content.push({
|
|
1339
|
+
type: "refusal",
|
|
1340
|
+
refusal: this.accumulatedRefusal
|
|
1341
|
+
});
|
|
1196
1342
|
for (const toolCall of this.toolCalls.values()) if (toolCall.name) content.push({
|
|
1197
1343
|
type: "function",
|
|
1198
1344
|
id: toolCall.id,
|