@posthog/ai 8.16.1 → 8.16.3
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 +157 -11
- package/dist/openai/index.cjs.map +1 -1
- package/dist/openai/index.mjs +157 -11
- 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 +4 -4
package/dist/anthropic/index.cjs
CHANGED
|
@@ -251,6 +251,10 @@ const redactor$1 = new BinaryContentRedactor();
|
|
|
251
251
|
const sanitize = (data, client) => isFullAiCaptureEnabled(client) ? data : redactor$1.redact(data);
|
|
252
252
|
const sanitizeAnthropic = (data, client) => sanitize(data, client);
|
|
253
253
|
//#endregion
|
|
254
|
+
//#region src/privacyMode.ts
|
|
255
|
+
/** Per-call settings can turn redaction on but never off. */
|
|
256
|
+
const isPrivacyModeEnabled = (client, privacyMode = false) => privacyMode === true || client?.privacyMode === true || client?.privacy_mode === true || client?.options?.privacyMode === true;
|
|
257
|
+
//#endregion
|
|
254
258
|
//#region src/utils.ts
|
|
255
259
|
const TOKEN_PROPERTY_KEYS = /* @__PURE__ */ new Set([
|
|
256
260
|
"$ai_input_tokens",
|
|
@@ -331,7 +335,6 @@ const mergeSystemPrompt = (params, provider) => {
|
|
|
331
335
|
}
|
|
332
336
|
return params.messages;
|
|
333
337
|
};
|
|
334
|
-
const isPrivacyModeEnabled = (client, privacyMode) => Boolean(client.privacy_mode || privacyMode);
|
|
335
338
|
function toSafeString(input) {
|
|
336
339
|
if (input === void 0 || input === null) return "";
|
|
337
340
|
if (typeof input === "string") return input;
|
|
@@ -412,11 +415,12 @@ function addDefaults(params) {
|
|
|
412
415
|
}
|
|
413
416
|
//#endregion
|
|
414
417
|
//#region package.json
|
|
415
|
-
var version = "8.16.
|
|
418
|
+
var version = "8.16.3";
|
|
416
419
|
//#endregion
|
|
417
420
|
//#region src/serializeError.ts
|
|
418
421
|
const DEFAULT_MAX_DEPTH = 3;
|
|
419
422
|
const MAX_STACK_LINES = 20;
|
|
423
|
+
const OMITTED_FIELD = "requestBodyValues";
|
|
420
424
|
function serializeError(value, depth = DEFAULT_MAX_DEPTH) {
|
|
421
425
|
if (depth < 0 || value === null || typeof value !== "object") return value;
|
|
422
426
|
if (value instanceof Error) {
|
|
@@ -425,16 +429,17 @@ function serializeError(value, depth = DEFAULT_MAX_DEPTH) {
|
|
|
425
429
|
message: value.message,
|
|
426
430
|
stack: truncateStack(value.stack)
|
|
427
431
|
};
|
|
428
|
-
for (const key of Object.keys(value)) out[key] = serializeError(value
|
|
432
|
+
for (const key of Object.keys(value)) if (key !== OMITTED_FIELD) out[key] = serializeError(Reflect.get(value, key), depth - 1);
|
|
429
433
|
if (value.cause !== void 0) out.cause = serializeError(value.cause, depth - 1);
|
|
430
434
|
return out;
|
|
431
435
|
}
|
|
432
436
|
if (Array.isArray(value)) return value.map((item) => serializeError(item, depth - 1));
|
|
433
437
|
return value;
|
|
434
438
|
}
|
|
439
|
+
const omitRequestBody = (key, value) => key === OMITTED_FIELD ? void 0 : value;
|
|
435
440
|
function stringifyError(error) {
|
|
436
441
|
try {
|
|
437
|
-
return JSON.stringify(sanitizeValues(serializeError(error)));
|
|
442
|
+
return JSON.stringify(sanitizeValues(serializeError(error)), omitRequestBody);
|
|
438
443
|
} catch {
|
|
439
444
|
if (error instanceof Error) return JSON.stringify({
|
|
440
445
|
name: error.name,
|
|
@@ -443,6 +448,105 @@ function stringifyError(error) {
|
|
|
443
448
|
return JSON.stringify({ message: String(error) });
|
|
444
449
|
}
|
|
445
450
|
}
|
|
451
|
+
const CLASS_NAME = /^[A-Za-z_$][A-Za-z0-9_$.]{0,127}$/;
|
|
452
|
+
const PROVIDER_CODE = /^[A-Za-z0-9_.:-]{1,64}$/;
|
|
453
|
+
const PARAM = /^[A-Za-z0-9_.[\]-]{1,128}$/;
|
|
454
|
+
const REQUEST_ID = /^[A-Za-z0-9_.:-]{1,128}$/;
|
|
455
|
+
const MAX_CAUSES = 3;
|
|
456
|
+
const readField = (value, key) => {
|
|
457
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") return;
|
|
458
|
+
try {
|
|
459
|
+
return Reflect.get(value, key);
|
|
460
|
+
} catch {
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
const matching = (value, grammar) => typeof value === "string" && grammar.test(value) ? value : void 0;
|
|
465
|
+
const firstMatching = (values, grammar) => {
|
|
466
|
+
for (const value of values) {
|
|
467
|
+
const match = matching(value, grammar);
|
|
468
|
+
if (match !== void 0) return match;
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
const className = (value) => {
|
|
472
|
+
if (!(value instanceof Error)) return "NonErrorThrown";
|
|
473
|
+
const name = readField(value, "name");
|
|
474
|
+
return firstMatching([
|
|
475
|
+
name === "Error" ? void 0 : name,
|
|
476
|
+
readField(readField(value, "constructor"), "name"),
|
|
477
|
+
name
|
|
478
|
+
], CLASS_NAME) ?? "Error";
|
|
479
|
+
};
|
|
480
|
+
const httpStatus = (error) => {
|
|
481
|
+
for (const key of ["status", "statusCode"]) {
|
|
482
|
+
const value = readField(error, key);
|
|
483
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599) return value;
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
const unwrapEnvelope = (body) => {
|
|
487
|
+
const inner = readField(body, "error");
|
|
488
|
+
return inner !== null && typeof inner === "object" ? inner : body;
|
|
489
|
+
};
|
|
490
|
+
const parsedResponseBody = (error) => {
|
|
491
|
+
const responseBody = readField(error, "responseBody");
|
|
492
|
+
if (typeof responseBody !== "string") return;
|
|
493
|
+
try {
|
|
494
|
+
return unwrapEnvelope(JSON.parse(responseBody));
|
|
495
|
+
} catch {
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
const causeNames = (error) => {
|
|
500
|
+
const names = [];
|
|
501
|
+
let cause = readField(error, "cause");
|
|
502
|
+
while (cause !== void 0 && cause !== null && names.length < MAX_CAUSES) {
|
|
503
|
+
names.push(className(cause));
|
|
504
|
+
cause = readField(cause, "cause");
|
|
505
|
+
}
|
|
506
|
+
return names;
|
|
507
|
+
};
|
|
508
|
+
const describeError = (error) => {
|
|
509
|
+
const sources = [
|
|
510
|
+
error,
|
|
511
|
+
unwrapEnvelope(readField(error, "error")),
|
|
512
|
+
parsedResponseBody(error)
|
|
513
|
+
];
|
|
514
|
+
const codes = /* @__PURE__ */ new Set();
|
|
515
|
+
for (const source of sources) for (const key of [
|
|
516
|
+
"code",
|
|
517
|
+
"type",
|
|
518
|
+
"status"
|
|
519
|
+
]) {
|
|
520
|
+
const code = matching(readField(source, key), PROVIDER_CODE);
|
|
521
|
+
if (code !== void 0) codes.add(code);
|
|
522
|
+
}
|
|
523
|
+
const status = httpStatus(error);
|
|
524
|
+
const param = firstMatching(sources.map((source) => readField(source, "param")), PARAM);
|
|
525
|
+
const requestId = firstMatching([readField(error, "requestID"), readField(error, "request_id")], REQUEST_ID);
|
|
526
|
+
const causes = causeNames(error);
|
|
527
|
+
let summary = className(error);
|
|
528
|
+
if (status !== void 0) summary += `: ${status}`;
|
|
529
|
+
for (const code of codes) summary += ` ${code}`;
|
|
530
|
+
if (param !== void 0) summary += ` param=${param}`;
|
|
531
|
+
if (requestId !== void 0) summary += ` request_id=${requestId}`;
|
|
532
|
+
if (causes.length > 0) summary += ` (caused by ${causes.join(", ")})`;
|
|
533
|
+
return summary;
|
|
534
|
+
};
|
|
535
|
+
/**
|
|
536
|
+
* Describes an error for `$ai_error` without its message, stack, or arbitrary fields, which
|
|
537
|
+
* routinely echo the prompt. Only structured fields that pass a strict grammar are kept.
|
|
538
|
+
* The format matches the Python SDK.
|
|
539
|
+
*/
|
|
540
|
+
function summarizeErrorForPrivacy(error) {
|
|
541
|
+
try {
|
|
542
|
+
return describeError(error);
|
|
543
|
+
} catch {
|
|
544
|
+
return error instanceof Error ? "Error" : "NonErrorThrown";
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
function formatAiError(error, privacyMode) {
|
|
548
|
+
return privacyMode ? summarizeErrorForPrivacy(error) : stringifyError(error);
|
|
549
|
+
}
|
|
446
550
|
function truncateStack(stack) {
|
|
447
551
|
if (!stack) return stack;
|
|
448
552
|
const lines = stack.split("\n");
|
|
@@ -450,6 +554,33 @@ function truncateStack(stack) {
|
|
|
450
554
|
return [...lines.slice(0, MAX_STACK_LINES), "... (truncated)"].join("\n");
|
|
451
555
|
}
|
|
452
556
|
//#endregion
|
|
557
|
+
//#region src/mcpCredentials.ts
|
|
558
|
+
const MCP_CREDENTIAL_FIELDS = ["headers", "authorization"];
|
|
559
|
+
const MCP_PROVIDER_TOOL_IDS = /* @__PURE__ */ new Set([
|
|
560
|
+
"openai.mcp",
|
|
561
|
+
"xai.mcp",
|
|
562
|
+
"google.mcp_server"
|
|
563
|
+
]);
|
|
564
|
+
const isMcpProviderTool = (tool) => (tool.type === "provider" || tool.type === "provider-defined") && typeof tool.id === "string" && MCP_PROVIDER_TOOL_IDS.has(tool.id);
|
|
565
|
+
const withoutMcpCredentials = (config) => {
|
|
566
|
+
const redacted = { ...config };
|
|
567
|
+
for (const field of MCP_CREDENTIAL_FIELDS) if (field in redacted) redacted[field] = "[REDACTED]";
|
|
568
|
+
return redacted;
|
|
569
|
+
};
|
|
570
|
+
/** Hides the credentials of a remote MCP tool definition; everything else is kept as sent. */
|
|
571
|
+
function redactMcpToolDefinition(tool) {
|
|
572
|
+
if (!isObject(tool)) return tool;
|
|
573
|
+
if (tool.type === "mcp") return withoutMcpCredentials(tool);
|
|
574
|
+
if (isMcpProviderTool(tool) && isObject(tool.args)) return {
|
|
575
|
+
...tool,
|
|
576
|
+
args: withoutMcpCredentials(tool.args)
|
|
577
|
+
};
|
|
578
|
+
return tool;
|
|
579
|
+
}
|
|
580
|
+
function redactMcpToolCredentials(tools) {
|
|
581
|
+
return Array.isArray(tools) ? tools.map(redactMcpToolDefinition) : tools;
|
|
582
|
+
}
|
|
583
|
+
//#endregion
|
|
453
584
|
//#region src/gatewayWarning.ts
|
|
454
585
|
const POSTHOG_AI_GATEWAY_HOSTS = [
|
|
455
586
|
"gateway.posthog.com",
|
|
@@ -512,13 +643,15 @@ const captureAiGeneration = async (client, options) => {
|
|
|
512
643
|
}
|
|
513
644
|
let exceptionId;
|
|
514
645
|
if (client.options?.enableExceptionAutocapture) {
|
|
515
|
-
|
|
516
|
-
|
|
646
|
+
if (!shouldRedact) {
|
|
647
|
+
exceptionId = (0, _posthog_core.uuidv7)();
|
|
648
|
+
client.captureException(options.error, void 0, { $ai_trace_id: traceId }, exceptionId);
|
|
649
|
+
}
|
|
517
650
|
if (typeof options.error === "object") options.error.__posthog_previously_captured_error = true;
|
|
518
651
|
}
|
|
519
652
|
errorData = {
|
|
520
653
|
$ai_is_error: true,
|
|
521
|
-
$ai_error:
|
|
654
|
+
$ai_error: formatAiError(options.error, shouldRedact),
|
|
522
655
|
$exception_event_id: exceptionId
|
|
523
656
|
};
|
|
524
657
|
}
|
|
@@ -559,7 +692,7 @@ const captureAiGeneration = async (client, options) => {
|
|
|
559
692
|
$ai_tokens_source: getTokensSource(options.properties),
|
|
560
693
|
...options.distinctId ? {} : { $process_person_profile: false },
|
|
561
694
|
...options.stopReason ? { $ai_stop_reason: options.stopReason } : {},
|
|
562
|
-
...options.tools ? { $ai_tools: options.tools } : {},
|
|
695
|
+
...options.tools ? { $ai_tools: redactMcpToolCredentials(options.tools) } : {},
|
|
563
696
|
...options.completionId ? { $ai_completion_id: options.completionId } : {},
|
|
564
697
|
...options.providerMetadata && Object.keys(options.providerMetadata).length > 0 ? { $ai_provider_metadata: options.providerMetadata } : {},
|
|
565
698
|
...errorData,
|