@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/gemini/index.cjs
CHANGED
|
@@ -233,6 +233,10 @@ function redactBase64DataUrl(str, mediaType) {
|
|
|
233
233
|
const sanitize = (data, client) => isFullAiCaptureEnabled(client) ? data : redactor$1.redact(data);
|
|
234
234
|
const sanitizeGemini = (data, client) => sanitize(data, client);
|
|
235
235
|
//#endregion
|
|
236
|
+
//#region src/privacyMode.ts
|
|
237
|
+
/** Per-call settings can turn redaction on but never off. */
|
|
238
|
+
const isPrivacyModeEnabled = (client, privacyMode = false) => privacyMode === true || client?.privacyMode === true || client?.privacy_mode === true || client?.options?.privacyMode === true;
|
|
239
|
+
//#endregion
|
|
236
240
|
//#region src/utils.ts
|
|
237
241
|
const TOKEN_PROPERTY_KEYS = /* @__PURE__ */ new Set([
|
|
238
242
|
"$ai_input_tokens",
|
|
@@ -379,7 +383,6 @@ const formatResponseGemini = (response, client) => {
|
|
|
379
383
|
});
|
|
380
384
|
return output;
|
|
381
385
|
};
|
|
382
|
-
const isPrivacyModeEnabled = (client, privacyMode) => Boolean(client.privacy_mode || privacyMode);
|
|
383
386
|
const withPrivacyMode = (client, privacyMode, input) => {
|
|
384
387
|
return isPrivacyModeEnabled(client, privacyMode) ? null : input;
|
|
385
388
|
};
|
|
@@ -463,11 +466,12 @@ function addDefaults(params) {
|
|
|
463
466
|
}
|
|
464
467
|
//#endregion
|
|
465
468
|
//#region package.json
|
|
466
|
-
var version = "8.16.
|
|
469
|
+
var version = "8.16.2";
|
|
467
470
|
//#endregion
|
|
468
471
|
//#region src/serializeError.ts
|
|
469
472
|
const DEFAULT_MAX_DEPTH = 3;
|
|
470
473
|
const MAX_STACK_LINES = 20;
|
|
474
|
+
const OMITTED_FIELD = "requestBodyValues";
|
|
471
475
|
function serializeError(value, depth = DEFAULT_MAX_DEPTH) {
|
|
472
476
|
if (depth < 0 || value === null || typeof value !== "object") return value;
|
|
473
477
|
if (value instanceof Error) {
|
|
@@ -476,16 +480,17 @@ function serializeError(value, depth = DEFAULT_MAX_DEPTH) {
|
|
|
476
480
|
message: value.message,
|
|
477
481
|
stack: truncateStack(value.stack)
|
|
478
482
|
};
|
|
479
|
-
for (const key of Object.keys(value)) out[key] = serializeError(value
|
|
483
|
+
for (const key of Object.keys(value)) if (key !== OMITTED_FIELD) out[key] = serializeError(Reflect.get(value, key), depth - 1);
|
|
480
484
|
if (value.cause !== void 0) out.cause = serializeError(value.cause, depth - 1);
|
|
481
485
|
return out;
|
|
482
486
|
}
|
|
483
487
|
if (Array.isArray(value)) return value.map((item) => serializeError(item, depth - 1));
|
|
484
488
|
return value;
|
|
485
489
|
}
|
|
490
|
+
const omitRequestBody = (key, value) => key === OMITTED_FIELD ? void 0 : value;
|
|
486
491
|
function stringifyError(error) {
|
|
487
492
|
try {
|
|
488
|
-
return JSON.stringify(sanitizeValues(serializeError(error)));
|
|
493
|
+
return JSON.stringify(sanitizeValues(serializeError(error)), omitRequestBody);
|
|
489
494
|
} catch {
|
|
490
495
|
if (error instanceof Error) return JSON.stringify({
|
|
491
496
|
name: error.name,
|
|
@@ -494,6 +499,105 @@ function stringifyError(error) {
|
|
|
494
499
|
return JSON.stringify({ message: String(error) });
|
|
495
500
|
}
|
|
496
501
|
}
|
|
502
|
+
const CLASS_NAME = /^[A-Za-z_$][A-Za-z0-9_$.]{0,127}$/;
|
|
503
|
+
const PROVIDER_CODE = /^[A-Za-z0-9_.:-]{1,64}$/;
|
|
504
|
+
const PARAM = /^[A-Za-z0-9_.[\]-]{1,128}$/;
|
|
505
|
+
const REQUEST_ID = /^[A-Za-z0-9_.:-]{1,128}$/;
|
|
506
|
+
const MAX_CAUSES = 3;
|
|
507
|
+
const readField = (value, key) => {
|
|
508
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") return;
|
|
509
|
+
try {
|
|
510
|
+
return Reflect.get(value, key);
|
|
511
|
+
} catch {
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
const matching = (value, grammar) => typeof value === "string" && grammar.test(value) ? value : void 0;
|
|
516
|
+
const firstMatching = (values, grammar) => {
|
|
517
|
+
for (const value of values) {
|
|
518
|
+
const match = matching(value, grammar);
|
|
519
|
+
if (match !== void 0) return match;
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
const className = (value) => {
|
|
523
|
+
if (!(value instanceof Error)) return "NonErrorThrown";
|
|
524
|
+
const name = readField(value, "name");
|
|
525
|
+
return firstMatching([
|
|
526
|
+
name === "Error" ? void 0 : name,
|
|
527
|
+
readField(readField(value, "constructor"), "name"),
|
|
528
|
+
name
|
|
529
|
+
], CLASS_NAME) ?? "Error";
|
|
530
|
+
};
|
|
531
|
+
const httpStatus = (error) => {
|
|
532
|
+
for (const key of ["status", "statusCode"]) {
|
|
533
|
+
const value = readField(error, key);
|
|
534
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599) return value;
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
const unwrapEnvelope = (body) => {
|
|
538
|
+
const inner = readField(body, "error");
|
|
539
|
+
return inner !== null && typeof inner === "object" ? inner : body;
|
|
540
|
+
};
|
|
541
|
+
const parsedResponseBody = (error) => {
|
|
542
|
+
const responseBody = readField(error, "responseBody");
|
|
543
|
+
if (typeof responseBody !== "string") return;
|
|
544
|
+
try {
|
|
545
|
+
return unwrapEnvelope(JSON.parse(responseBody));
|
|
546
|
+
} catch {
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
const causeNames = (error) => {
|
|
551
|
+
const names = [];
|
|
552
|
+
let cause = readField(error, "cause");
|
|
553
|
+
while (cause !== void 0 && cause !== null && names.length < MAX_CAUSES) {
|
|
554
|
+
names.push(className(cause));
|
|
555
|
+
cause = readField(cause, "cause");
|
|
556
|
+
}
|
|
557
|
+
return names;
|
|
558
|
+
};
|
|
559
|
+
const describeError = (error) => {
|
|
560
|
+
const sources = [
|
|
561
|
+
error,
|
|
562
|
+
unwrapEnvelope(readField(error, "error")),
|
|
563
|
+
parsedResponseBody(error)
|
|
564
|
+
];
|
|
565
|
+
const codes = /* @__PURE__ */ new Set();
|
|
566
|
+
for (const source of sources) for (const key of [
|
|
567
|
+
"code",
|
|
568
|
+
"type",
|
|
569
|
+
"status"
|
|
570
|
+
]) {
|
|
571
|
+
const code = matching(readField(source, key), PROVIDER_CODE);
|
|
572
|
+
if (code !== void 0) codes.add(code);
|
|
573
|
+
}
|
|
574
|
+
const status = httpStatus(error);
|
|
575
|
+
const param = firstMatching(sources.map((source) => readField(source, "param")), PARAM);
|
|
576
|
+
const requestId = firstMatching([readField(error, "requestID"), readField(error, "request_id")], REQUEST_ID);
|
|
577
|
+
const causes = causeNames(error);
|
|
578
|
+
let summary = className(error);
|
|
579
|
+
if (status !== void 0) summary += `: ${status}`;
|
|
580
|
+
for (const code of codes) summary += ` ${code}`;
|
|
581
|
+
if (param !== void 0) summary += ` param=${param}`;
|
|
582
|
+
if (requestId !== void 0) summary += ` request_id=${requestId}`;
|
|
583
|
+
if (causes.length > 0) summary += ` (caused by ${causes.join(", ")})`;
|
|
584
|
+
return summary;
|
|
585
|
+
};
|
|
586
|
+
/**
|
|
587
|
+
* Describes an error for `$ai_error` without its message, stack, or arbitrary fields, which
|
|
588
|
+
* routinely echo the prompt. Only structured fields that pass a strict grammar are kept.
|
|
589
|
+
* The format matches the Python SDK.
|
|
590
|
+
*/
|
|
591
|
+
function summarizeErrorForPrivacy(error) {
|
|
592
|
+
try {
|
|
593
|
+
return describeError(error);
|
|
594
|
+
} catch {
|
|
595
|
+
return error instanceof Error ? "Error" : "NonErrorThrown";
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
function formatAiError(error, privacyMode) {
|
|
599
|
+
return privacyMode ? summarizeErrorForPrivacy(error) : stringifyError(error);
|
|
600
|
+
}
|
|
497
601
|
function truncateStack(stack) {
|
|
498
602
|
if (!stack) return stack;
|
|
499
603
|
const lines = stack.split("\n");
|
|
@@ -501,6 +605,33 @@ function truncateStack(stack) {
|
|
|
501
605
|
return [...lines.slice(0, MAX_STACK_LINES), "... (truncated)"].join("\n");
|
|
502
606
|
}
|
|
503
607
|
//#endregion
|
|
608
|
+
//#region src/mcpCredentials.ts
|
|
609
|
+
const MCP_CREDENTIAL_FIELDS = ["headers", "authorization"];
|
|
610
|
+
const MCP_PROVIDER_TOOL_IDS = /* @__PURE__ */ new Set([
|
|
611
|
+
"openai.mcp",
|
|
612
|
+
"xai.mcp",
|
|
613
|
+
"google.mcp_server"
|
|
614
|
+
]);
|
|
615
|
+
const isMcpProviderTool = (tool) => (tool.type === "provider" || tool.type === "provider-defined") && typeof tool.id === "string" && MCP_PROVIDER_TOOL_IDS.has(tool.id);
|
|
616
|
+
const withoutMcpCredentials = (config) => {
|
|
617
|
+
const redacted = { ...config };
|
|
618
|
+
for (const field of MCP_CREDENTIAL_FIELDS) if (field in redacted) redacted[field] = "[REDACTED]";
|
|
619
|
+
return redacted;
|
|
620
|
+
};
|
|
621
|
+
/** Hides the credentials of a remote MCP tool definition; everything else is kept as sent. */
|
|
622
|
+
function redactMcpToolDefinition(tool) {
|
|
623
|
+
if (!isObject(tool)) return tool;
|
|
624
|
+
if (tool.type === "mcp") return withoutMcpCredentials(tool);
|
|
625
|
+
if (isMcpProviderTool(tool) && isObject(tool.args)) return {
|
|
626
|
+
...tool,
|
|
627
|
+
args: withoutMcpCredentials(tool.args)
|
|
628
|
+
};
|
|
629
|
+
return tool;
|
|
630
|
+
}
|
|
631
|
+
function redactMcpToolCredentials(tools) {
|
|
632
|
+
return Array.isArray(tools) ? tools.map(redactMcpToolDefinition) : tools;
|
|
633
|
+
}
|
|
634
|
+
//#endregion
|
|
504
635
|
//#region src/gatewayWarning.ts
|
|
505
636
|
const POSTHOG_AI_GATEWAY_HOSTS = [
|
|
506
637
|
"gateway.posthog.com",
|
|
@@ -563,13 +694,15 @@ const captureAiGeneration = async (client, options) => {
|
|
|
563
694
|
}
|
|
564
695
|
let exceptionId;
|
|
565
696
|
if (client.options?.enableExceptionAutocapture) {
|
|
566
|
-
|
|
567
|
-
|
|
697
|
+
if (!shouldRedact) {
|
|
698
|
+
exceptionId = (0, _posthog_core.uuidv7)();
|
|
699
|
+
client.captureException(options.error, void 0, { $ai_trace_id: traceId }, exceptionId);
|
|
700
|
+
}
|
|
568
701
|
if (typeof options.error === "object") options.error.__posthog_previously_captured_error = true;
|
|
569
702
|
}
|
|
570
703
|
errorData = {
|
|
571
704
|
$ai_is_error: true,
|
|
572
|
-
$ai_error:
|
|
705
|
+
$ai_error: formatAiError(options.error, shouldRedact),
|
|
573
706
|
$exception_event_id: exceptionId
|
|
574
707
|
};
|
|
575
708
|
}
|
|
@@ -610,7 +743,7 @@ const captureAiGeneration = async (client, options) => {
|
|
|
610
743
|
$ai_tokens_source: getTokensSource(options.properties),
|
|
611
744
|
...options.distinctId ? {} : { $process_person_profile: false },
|
|
612
745
|
...options.stopReason ? { $ai_stop_reason: options.stopReason } : {},
|
|
613
|
-
...options.tools ? { $ai_tools: options.tools } : {},
|
|
746
|
+
...options.tools ? { $ai_tools: redactMcpToolCredentials(options.tools) } : {},
|
|
614
747
|
...options.completionId ? { $ai_completion_id: options.completionId } : {},
|
|
615
748
|
...options.providerMetadata && Object.keys(options.providerMetadata).length > 0 ? { $ai_provider_metadata: options.providerMetadata } : {},
|
|
616
749
|
...errorData,
|