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