@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.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",
|
|
@@ -307,6 +311,10 @@ const formatResponseOpenAI = (response) => {
|
|
|
307
311
|
type: "text",
|
|
308
312
|
text: choice.message.content
|
|
309
313
|
});
|
|
314
|
+
if (choice.message.refusal) content.push({
|
|
315
|
+
type: "refusal",
|
|
316
|
+
refusal: choice.message.refusal
|
|
317
|
+
});
|
|
310
318
|
if (choice.message.tool_calls) for (const toolCall of choice.message.tool_calls) {
|
|
311
319
|
const call = toolCall.type === "custom" ? toolCall.custom : toolCall.function;
|
|
312
320
|
if (!call) continue;
|
|
@@ -370,7 +378,6 @@ const formatResponseOpenAI = (response) => {
|
|
|
370
378
|
}
|
|
371
379
|
return output;
|
|
372
380
|
};
|
|
373
|
-
const isPrivacyModeEnabled = (client, privacyMode) => Boolean(client.privacy_mode || privacyMode);
|
|
374
381
|
const withPrivacyMode = (client, privacyMode, input) => {
|
|
375
382
|
return isPrivacyModeEnabled(client, privacyMode) ? null : input;
|
|
376
383
|
};
|
|
@@ -541,11 +548,12 @@ function formatOpenAIResponsesInput(input, instructions) {
|
|
|
541
548
|
}
|
|
542
549
|
//#endregion
|
|
543
550
|
//#region package.json
|
|
544
|
-
var version = "8.16.
|
|
551
|
+
var version = "8.16.2";
|
|
545
552
|
//#endregion
|
|
546
553
|
//#region src/serializeError.ts
|
|
547
554
|
const DEFAULT_MAX_DEPTH = 3;
|
|
548
555
|
const MAX_STACK_LINES = 20;
|
|
556
|
+
const OMITTED_FIELD = "requestBodyValues";
|
|
549
557
|
function serializeError(value, depth = DEFAULT_MAX_DEPTH) {
|
|
550
558
|
if (depth < 0 || value === null || typeof value !== "object") return value;
|
|
551
559
|
if (value instanceof Error) {
|
|
@@ -554,16 +562,17 @@ function serializeError(value, depth = DEFAULT_MAX_DEPTH) {
|
|
|
554
562
|
message: value.message,
|
|
555
563
|
stack: truncateStack(value.stack)
|
|
556
564
|
};
|
|
557
|
-
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);
|
|
558
566
|
if (value.cause !== void 0) out.cause = serializeError(value.cause, depth - 1);
|
|
559
567
|
return out;
|
|
560
568
|
}
|
|
561
569
|
if (Array.isArray(value)) return value.map((item) => serializeError(item, depth - 1));
|
|
562
570
|
return value;
|
|
563
571
|
}
|
|
572
|
+
const omitRequestBody = (key, value) => key === OMITTED_FIELD ? void 0 : value;
|
|
564
573
|
function stringifyError(error) {
|
|
565
574
|
try {
|
|
566
|
-
return JSON.stringify(sanitizeValues(serializeError(error)));
|
|
575
|
+
return JSON.stringify(sanitizeValues(serializeError(error)), omitRequestBody);
|
|
567
576
|
} catch {
|
|
568
577
|
if (error instanceof Error) return JSON.stringify({
|
|
569
578
|
name: error.name,
|
|
@@ -572,6 +581,105 @@ function stringifyError(error) {
|
|
|
572
581
|
return JSON.stringify({ message: String(error) });
|
|
573
582
|
}
|
|
574
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
|
+
}
|
|
575
683
|
function truncateStack(stack) {
|
|
576
684
|
if (!stack) return stack;
|
|
577
685
|
const lines = stack.split("\n");
|
|
@@ -579,6 +687,33 @@ function truncateStack(stack) {
|
|
|
579
687
|
return [...lines.slice(0, MAX_STACK_LINES), "... (truncated)"].join("\n");
|
|
580
688
|
}
|
|
581
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
|
|
582
717
|
//#region src/gatewayWarning.ts
|
|
583
718
|
const POSTHOG_AI_GATEWAY_HOSTS = [
|
|
584
719
|
"gateway.posthog.com",
|
|
@@ -641,13 +776,15 @@ const captureAiGeneration$1 = async (client, options) => {
|
|
|
641
776
|
}
|
|
642
777
|
let exceptionId;
|
|
643
778
|
if (client.options?.enableExceptionAutocapture) {
|
|
644
|
-
|
|
645
|
-
|
|
779
|
+
if (!shouldRedact) {
|
|
780
|
+
exceptionId = uuidv7();
|
|
781
|
+
client.captureException(options.error, void 0, { $ai_trace_id: traceId }, exceptionId);
|
|
782
|
+
}
|
|
646
783
|
if (typeof options.error === "object") options.error.__posthog_previously_captured_error = true;
|
|
647
784
|
}
|
|
648
785
|
errorData = {
|
|
649
786
|
$ai_is_error: true,
|
|
650
|
-
$ai_error:
|
|
787
|
+
$ai_error: formatAiError(options.error, shouldRedact),
|
|
651
788
|
$exception_event_id: exceptionId
|
|
652
789
|
};
|
|
653
790
|
}
|
|
@@ -688,7 +825,7 @@ const captureAiGeneration$1 = async (client, options) => {
|
|
|
688
825
|
$ai_tokens_source: getTokensSource(options.properties),
|
|
689
826
|
...options.distinctId ? {} : { $process_person_profile: false },
|
|
690
827
|
...options.stopReason ? { $ai_stop_reason: options.stopReason } : {},
|
|
691
|
-
...options.tools ? { $ai_tools: options.tools } : {},
|
|
828
|
+
...options.tools ? { $ai_tools: redactMcpToolCredentials(options.tools) } : {},
|
|
692
829
|
...options.completionId ? { $ai_completion_id: options.completionId } : {},
|
|
693
830
|
...options.providerMetadata && Object.keys(options.providerMetadata).length > 0 ? { $ai_provider_metadata: options.providerMetadata } : {},
|
|
694
831
|
...errorData,
|
|
@@ -1142,6 +1279,7 @@ function monitoredStreamTee(source, createStream) {
|
|
|
1142
1279
|
var OpenAIChatStreamAccumulator = class {
|
|
1143
1280
|
constructor() {
|
|
1144
1281
|
this.accumulatedContent = "";
|
|
1282
|
+
this.accumulatedRefusal = "";
|
|
1145
1283
|
this.usage = { webSearchCount: 0 };
|
|
1146
1284
|
this.toolCalls = /* @__PURE__ */ new Map();
|
|
1147
1285
|
}
|
|
@@ -1158,6 +1296,10 @@ var OpenAIChatStreamAccumulator = class {
|
|
|
1158
1296
|
this.firstTokenTime ??= receivedAt;
|
|
1159
1297
|
this.accumulatedContent += choice.delta.content;
|
|
1160
1298
|
}
|
|
1299
|
+
if (choice?.delta?.refusal) {
|
|
1300
|
+
this.firstTokenTime ??= receivedAt;
|
|
1301
|
+
this.accumulatedRefusal += choice.delta.refusal;
|
|
1302
|
+
}
|
|
1161
1303
|
if (Array.isArray(choice?.delta?.tool_calls)) {
|
|
1162
1304
|
this.firstTokenTime ??= receivedAt;
|
|
1163
1305
|
for (const toolCall of choice.delta.tool_calls) {
|
|
@@ -1189,6 +1331,10 @@ var OpenAIChatStreamAccumulator = class {
|
|
|
1189
1331
|
type: "text",
|
|
1190
1332
|
text: this.accumulatedContent
|
|
1191
1333
|
});
|
|
1334
|
+
if (this.accumulatedRefusal) content.push({
|
|
1335
|
+
type: "refusal",
|
|
1336
|
+
refusal: this.accumulatedRefusal
|
|
1337
|
+
});
|
|
1192
1338
|
for (const toolCall of this.toolCalls.values()) if (toolCall.name) content.push({
|
|
1193
1339
|
type: "function",
|
|
1194
1340
|
id: toolCall.id,
|