agentid-sdk 0.1.36 → 0.1.38

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/dist/index.js CHANGED
@@ -21,27 +21,105 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  AgentID: () => AgentID,
24
+ AgentIDWorkflowStep: () => AgentIDWorkflowStep,
25
+ AgentIDWorkflowTrail: () => AgentIDWorkflowTrail,
24
26
  DependencyError: () => DependencyError,
25
27
  InjectionScanner: () => InjectionScanner,
26
28
  OpenAIAdapter: () => OpenAIAdapter,
27
29
  PIIManager: () => PIIManager,
28
30
  SecurityBlockError: () => SecurityBlockError,
31
+ createAgentIdCorrelationId: () => createAgentIdCorrelationId,
32
+ createAgentIdOperationLog: () => createAgentIdOperationLog,
33
+ createAgentIdTelemetryContext: () => createAgentIdTelemetryContext,
34
+ createAgentIdWorkflowTrail: () => createAgentIdWorkflowTrail,
29
35
  getInjectionScanner: () => getInjectionScanner,
30
36
  scanWithRegex: () => scanWithRegex
31
37
  });
32
38
  module.exports = __toCommonJS(index_exports);
33
39
 
34
40
  // src/adapters.ts
41
+ function getLastUserMessage(req) {
42
+ const messages = req?.messages;
43
+ if (!Array.isArray(messages)) return null;
44
+ let lastUser = null;
45
+ for (const msg of messages) {
46
+ if (msg && typeof msg === "object" && msg.role === "user") {
47
+ lastUser = msg;
48
+ }
49
+ }
50
+ return lastUser;
51
+ }
52
+ function normalizeFilename(value, fallback) {
53
+ if (typeof value !== "string") {
54
+ return fallback;
55
+ }
56
+ const trimmed = value.trim();
57
+ return trimmed.length > 0 ? trimmed : fallback;
58
+ }
59
+ function parseDataUrl(value) {
60
+ if (!value.startsWith("data:")) {
61
+ return null;
62
+ }
63
+ const commaIndex = value.indexOf(",");
64
+ if (commaIndex === -1) {
65
+ return null;
66
+ }
67
+ const header = value.slice(5, commaIndex);
68
+ if (!/;base64/i.test(header)) {
69
+ return null;
70
+ }
71
+ const mimeType = header.split(";")[0]?.trim().toLowerCase() || null;
72
+ return { mimeType };
73
+ }
74
+ function inferAttachmentExtension(mimeType) {
75
+ switch (mimeType) {
76
+ case "application/pdf":
77
+ return "pdf";
78
+ case "image/png":
79
+ return "png";
80
+ case "image/jpeg":
81
+ return "jpg";
82
+ case "image/webp":
83
+ return "webp";
84
+ case "image/gif":
85
+ return "gif";
86
+ case "text/plain":
87
+ return "txt";
88
+ default:
89
+ return "bin";
90
+ }
91
+ }
92
+ function defaultFilenameForMimeType(mimeType) {
93
+ return `attachment.${inferAttachmentExtension(mimeType)}`;
94
+ }
95
+ function normalizeFileAttachment(part) {
96
+ const file = part?.file;
97
+ const rawContent = typeof file?.file_data === "string" && file.file_data.trim().length > 0 ? file.file_data.trim() : null;
98
+ if (!rawContent) {
99
+ return null;
100
+ }
101
+ const detectedMimeType = parseDataUrl(rawContent)?.mimeType ?? null;
102
+ return {
103
+ filename: normalizeFilename(file?.filename, defaultFilenameForMimeType(detectedMimeType)),
104
+ ...detectedMimeType ? { mime_type: detectedMimeType } : {},
105
+ content_base64: rawContent
106
+ };
107
+ }
108
+ function normalizeImageAttachment(part) {
109
+ const imageUrl = typeof part?.image_url?.url === "string" && part.image_url.url.trim().length > 0 ? part.image_url.url.trim() : null;
110
+ if (!imageUrl || !imageUrl.startsWith("data:")) {
111
+ return null;
112
+ }
113
+ const detectedMimeType = parseDataUrl(imageUrl)?.mimeType ?? "image/png";
114
+ return {
115
+ filename: defaultFilenameForMimeType(detectedMimeType),
116
+ mime_type: detectedMimeType,
117
+ content_base64: imageUrl
118
+ };
119
+ }
35
120
  var OpenAIAdapter = class {
36
121
  extractInput(req) {
37
- const messages = req?.messages;
38
- if (!Array.isArray(messages)) return null;
39
- let lastUser = null;
40
- for (const msg of messages) {
41
- if (msg && typeof msg === "object" && msg.role === "user") {
42
- lastUser = msg;
43
- }
44
- }
122
+ const lastUser = getLastUserMessage(req);
45
123
  if (!lastUser) return null;
46
124
  const content = lastUser.content;
47
125
  if (typeof content === "string") return content;
@@ -56,6 +134,34 @@ var OpenAIAdapter = class {
56
134
  }
57
135
  return null;
58
136
  }
137
+ extractAttachments(req) {
138
+ const lastUser = getLastUserMessage(req);
139
+ if (!lastUser) return [];
140
+ const content = lastUser?.content;
141
+ if (!Array.isArray(content)) {
142
+ return [];
143
+ }
144
+ const attachments = [];
145
+ for (const part of content) {
146
+ if (!part || typeof part !== "object") {
147
+ continue;
148
+ }
149
+ if (part.type === "file") {
150
+ const attachment = normalizeFileAttachment(part);
151
+ if (attachment) {
152
+ attachments.push(attachment);
153
+ }
154
+ continue;
155
+ }
156
+ if (part.type === "image_url") {
157
+ const attachment = normalizeImageAttachment(part);
158
+ if (attachment) {
159
+ attachments.push(attachment);
160
+ }
161
+ }
162
+ }
163
+ return attachments;
164
+ }
59
165
  getModelName(req, res) {
60
166
  const model = res?.model ?? req?.model ?? "unknown";
61
167
  return String(model);
@@ -75,7 +181,7 @@ var OpenAIAdapter = class {
75
181
 
76
182
  // src/sdk-version.ts
77
183
  var FALLBACK_SDK_VERSION = "js-0.0.0-dev";
78
- var AGENTID_SDK_VERSION_HEADER = "js-0.1.36".trim().length > 0 ? "js-0.1.36" : FALLBACK_SDK_VERSION;
184
+ var AGENTID_SDK_VERSION_HEADER = "js-0.1.38".trim().length > 0 ? "js-0.1.38" : FALLBACK_SDK_VERSION;
79
185
 
80
186
  // src/pii-national-identifiers.ts
81
187
  var MAX_CANDIDATES_PER_RULE = 256;
@@ -939,8 +1045,173 @@ function detectNationalIdentifiers(text, options = {}) {
939
1045
  return results;
940
1046
  }
941
1047
 
1048
+ // src/secret-patterns.ts
1049
+ var SDK_SECRET_PATTERN_DEFINITIONS = [
1050
+ {
1051
+ id: "openai_api_key",
1052
+ placeholderType: "OPENAI_API_KEY",
1053
+ patternSource: "\\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}\\b",
1054
+ flags: "iu",
1055
+ prefilterTerms: ["sk-", "proj-", "openai"]
1056
+ },
1057
+ {
1058
+ id: "aws_access_key",
1059
+ placeholderType: "AWS_ACCESS_KEY",
1060
+ patternSource: "\\b(?:AKIA|ASIA)[A-Z0-9]{16}\\b",
1061
+ flags: "iu",
1062
+ prefilterTerms: ["akia", "asia", "aws"]
1063
+ },
1064
+ {
1065
+ id: "github_token",
1066
+ placeholderType: "GITHUB_TOKEN",
1067
+ patternSource: "\\b(?:gh[pousr]_[A-Za-z0-9]{24,255}|github_pat_[A-Za-z0-9_]{20,255})\\b",
1068
+ flags: "iu",
1069
+ prefilterTerms: ["ghp_", "gho_", "ghu_", "ghs_", "ghr_", "github_pat_"]
1070
+ },
1071
+ {
1072
+ id: "slack_token",
1073
+ placeholderType: "SLACK_TOKEN",
1074
+ patternSource: "\\bxox(?:a|b|p|r|s)-[A-Za-z0-9-]{10,200}\\b",
1075
+ flags: "iu",
1076
+ prefilterTerms: ["xoxa-", "xoxb-", "xoxp-", "xoxr-", "xoxs-", "slack"]
1077
+ },
1078
+ {
1079
+ id: "slack_webhook_url",
1080
+ placeholderType: "SLACK_WEBHOOK_URL",
1081
+ patternSource: "https:\\/\\/hooks\\.slack\\.com\\/services\\/[A-Za-z0-9/_-]{20,}",
1082
+ flags: "iu",
1083
+ prefilterTerms: ["hooks.slack.com/services", "slack"]
1084
+ },
1085
+ {
1086
+ id: "discord_webhook_url",
1087
+ placeholderType: "DISCORD_WEBHOOK_URL",
1088
+ patternSource: "https:\\/\\/discord(?:app)?\\.com\\/api\\/webhooks\\/\\d+\\/[A-Za-z0-9_-]{16,}",
1089
+ flags: "iu",
1090
+ prefilterTerms: ["discord.com/api/webhooks", "discordapp.com/api/webhooks", "discord"]
1091
+ },
1092
+ {
1093
+ id: "stripe_secret_key",
1094
+ placeholderType: "STRIPE_SECRET_KEY",
1095
+ patternSource: "\\b(?:sk|pk|ak|rk)_(?:live|test)_[A-Za-z0-9]+\\b",
1096
+ flags: "iu",
1097
+ prefilterTerms: [
1098
+ "sk_live_",
1099
+ "pk_live_",
1100
+ "sk_test_",
1101
+ "pk_test_",
1102
+ "ak_live_",
1103
+ "ak_test_",
1104
+ "rk_live_",
1105
+ "rk_test_",
1106
+ "stripe"
1107
+ ]
1108
+ },
1109
+ {
1110
+ id: "google_api_key",
1111
+ placeholderType: "GOOGLE_API_KEY",
1112
+ patternSource: "\\bAIza[0-9A-Za-z_-]{35}\\b",
1113
+ flags: "iu",
1114
+ prefilterTerms: ["aiza", "google"]
1115
+ },
1116
+ {
1117
+ id: "anthropic_api_key",
1118
+ placeholderType: "ANTHROPIC_API_KEY",
1119
+ patternSource: "\\bsk-ant-(?:api\\d{2}-)?[A-Za-z0-9_-]{20,}\\b",
1120
+ flags: "iu",
1121
+ prefilterTerms: ["sk-ant-", "anthropic"]
1122
+ },
1123
+ {
1124
+ id: "evm_private_key",
1125
+ placeholderType: "EVM_PRIVATE_KEY",
1126
+ patternSource: "\\b0x[a-fA-F0-9]{64}\\b",
1127
+ flags: "iu",
1128
+ prefilterTerms: ["0x", "ethereum", "evm", "private key"]
1129
+ },
1130
+ {
1131
+ id: "jwt_token",
1132
+ placeholderType: "JWT_TOKEN",
1133
+ patternSource: "\\beyJ[A-Za-z0-9_-]{6,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\b",
1134
+ flags: "iu",
1135
+ prefilterTerms: ["eyj", "jwt", "bearer"]
1136
+ },
1137
+ {
1138
+ id: "bearer_token",
1139
+ placeholderType: "BEARER_TOKEN",
1140
+ patternSource: "\\bauthorization\\b\\s*[:=]\\s*bearer\\s+[A-Za-z0-9._~+\\/-]{16,}|\\bbearer\\s+[A-Za-z0-9._~+\\/-]{24,}",
1141
+ flags: "iu",
1142
+ prefilterTerms: ["authorization", "bearer"]
1143
+ },
1144
+ {
1145
+ id: "api_key_header",
1146
+ placeholderType: "API_KEY_HEADER",
1147
+ patternSource: "\\bx[-_]?api[-_]?key\\b\\s*[:=]\\s*[A-Za-z0-9._~+\\/-]{16,}",
1148
+ flags: "iu",
1149
+ prefilterTerms: ["x-api-key", "api-key", "x_api_key", "api_key"]
1150
+ },
1151
+ {
1152
+ id: "credential_assignment",
1153
+ placeholderType: "CREDENTIAL_ASSIGNMENT",
1154
+ patternSource: `(?:\\b|["'])(?:api(?:[_-]?|\\s+)key|access(?:[_-]?|\\s+)token|auth(?:[_-]?|\\s+)token|client(?:[_-]?|\\s+)secret|private(?:[_-]?|\\s+)key)(?:\\b|["'])\\s*(?::|=|=>)\\s*(?:"[A-Za-z0-9._~+\\/=:-]{16,}"|'[A-Za-z0-9._~+\\/=:-]{16,}'|[A-Za-z0-9._~+\\/=:-]{16,})`,
1155
+ flags: "iu",
1156
+ prefilterTerms: [
1157
+ "api key",
1158
+ "apikey",
1159
+ "api_key",
1160
+ "access token",
1161
+ "access_token",
1162
+ "auth token",
1163
+ "client secret",
1164
+ "private key"
1165
+ ]
1166
+ },
1167
+ {
1168
+ id: "password_assignment",
1169
+ placeholderType: "PASSWORD_ASSIGNMENT",
1170
+ patternSource: `(?:\\b|["'])(?:password|passwd|pwd)(?:\\b|["'])\\s*(?:(?::|=|=>)|(?:is|are|was|were)\\b)\\s*(?:"[A-Za-z0-9._~!@#$%^&*+=\\/-]{8,}"|'[A-Za-z0-9._~!@#$%^&*+=\\/-]{8,}'|[A-Za-z0-9._~!@#$%^&*+=\\/-]{8,})`,
1171
+ flags: "iu",
1172
+ prefilterTerms: ["password", "passwd", "pwd"]
1173
+ },
1174
+ {
1175
+ id: "private_key_material",
1176
+ placeholderType: "PRIVATE_KEY_MATERIAL",
1177
+ patternSource: "-----BEGIN (?:(?:RSA |EC |OPENSSH |DSA )?PRIVATE KEY|PGP PRIVATE KEY BLOCK|CERTIFICATE)-----[\\s\\S]{20,12000}(?:-----END (?:(?:RSA |EC |OPENSSH |DSA )?PRIVATE KEY|PGP PRIVATE KEY BLOCK|CERTIFICATE)-----|$)",
1178
+ flags: "iu",
1179
+ prefilterTerms: ["begin private key", "begin pgp private key block", "private key"]
1180
+ },
1181
+ {
1182
+ id: "azure_connection_string",
1183
+ placeholderType: "AZURE_CONNECTION_STRING",
1184
+ patternSource: "\\bDefaultEndpointsProtocol=https;AccountName=[A-Za-z0-9.-]{3,};AccountKey=[A-Za-z0-9+/=]{20,}(?:;EndpointSuffix=[A-Za-z0-9.-]+)?\\b",
1185
+ flags: "iu",
1186
+ prefilterTerms: ["defaultendpointsprotocol", "accountname", "accountkey", "azure"]
1187
+ },
1188
+ {
1189
+ id: "azure_sas_token",
1190
+ placeholderType: "AZURE_SAS_TOKEN",
1191
+ patternSource: "\\bsv=[^\\s&]{2,}&[^\\s]{0,200}\\bsig=[A-Za-z0-9%/+_-]{16,}",
1192
+ flags: "iu",
1193
+ prefilterTerms: ["sv=", "sig=", "accountkey", "azure"]
1194
+ }
1195
+ ];
1196
+ function ensureGlobalFlag(flags) {
1197
+ const normalized = new Set(flags.split(""));
1198
+ normalized.add("g");
1199
+ return [...normalized].join("");
1200
+ }
1201
+ var COMPILED_SDK_SECRET_PATTERNS = SDK_SECRET_PATTERN_DEFINITIONS.map((definition) => ({
1202
+ ...definition,
1203
+ scanRegex: new RegExp(definition.patternSource, ensureGlobalFlag(definition.flags)),
1204
+ prefilterTermsLower: definition.prefilterTerms.map((term) => term.toLowerCase())
1205
+ }));
1206
+ function getSdkSecretDetectionMatchers() {
1207
+ return COMPILED_SDK_SECRET_PATTERNS;
1208
+ }
1209
+
942
1210
  // src/pii.ts
943
1211
  var defaultScanDeadlineMs = 100;
1212
+ var sdkSecretMatchers = getSdkSecretDetectionMatchers();
1213
+ var DISCORD_WEBHOOK_TOKEN_RE = /https:\/\/discord(?:app)?\.com\/api\/webhooks\/\d+\/([A-Za-z0-9_-]{16,})/giu;
1214
+ var BASIC_AUTH_PASSWORD_RE = /\/\/[^:\s/?#@]+:([^@\s/?#]+)@/giu;
944
1215
  function countDigits2(value) {
945
1216
  let count = 0;
946
1217
  for (const ch of value) {
@@ -965,15 +1236,32 @@ function luhnCheck(value) {
965
1236
  return sum % 10 === 0;
966
1237
  }
967
1238
  function normalizeDetections(text, detections) {
968
- const sorted = detections.filter((d) => d.start >= 0 && d.end > d.start && d.end <= text.length).sort((a, b) => a.start - b.start || b.end - b.start - (a.end - a.start));
1239
+ const sorted = detections.filter((d) => d.start >= 0 && d.end > d.start && d.end <= text.length).sort(
1240
+ (a, b) => detectionPriority(b.type) - detectionPriority(a.type) || a.start - b.start || b.end - b.start - (a.end - a.start)
1241
+ );
969
1242
  const kept = [];
970
- let cursor = 0;
971
1243
  for (const d of sorted) {
972
- if (d.start < cursor) continue;
1244
+ if (kept.some((candidate) => rangesOverlap(candidate, d))) continue;
973
1245
  kept.push(d);
974
- cursor = d.end;
975
1246
  }
976
- return kept;
1247
+ return kept.sort((a, b) => a.start - b.start || a.end - b.end);
1248
+ }
1249
+ function rangesOverlap(left, right) {
1250
+ return left.start < right.end && right.start < left.end;
1251
+ }
1252
+ function detectionPriority(type) {
1253
+ if (/^(?:OPENAI_API_KEY|AWS_ACCESS_KEY|GITHUB_TOKEN|SLACK_TOKEN|SLACK_WEBHOOK_URL|DISCORD_WEBHOOK_URL|STRIPE_SECRET_KEY|GOOGLE_API_KEY|ANTHROPIC_API_KEY|EVM_PRIVATE_KEY|JWT_TOKEN|BEARER_TOKEN|API_KEY_HEADER|AZURE_CONNECTION_STRING|AZURE_SAS_TOKEN)$/u.test(
1254
+ type
1255
+ )) {
1256
+ return 100;
1257
+ }
1258
+ if (/^(?:CREDENTIAL_ASSIGNMENT|PASSWORD_ASSIGNMENT|PRIVATE_KEY_MATERIAL|ENV_SECRET_ASSIGNMENT)$/u.test(type)) {
1259
+ return 80;
1260
+ }
1261
+ if (type === "PERSON_NAME" || type === "PERSON") {
1262
+ return 10;
1263
+ }
1264
+ return 50;
977
1265
  }
978
1266
  var PHONE_CONTEXT_KEYWORDS = [
979
1267
  "tel",
@@ -1008,6 +1296,59 @@ var PHONE_CONTEXT_RE = new RegExp(
1008
1296
  "iu"
1009
1297
  );
1010
1298
  var PERSON_NAME_STOPWORDS = /* @__PURE__ */ new Set([
1299
+ "name",
1300
+ "names",
1301
+ "namen",
1302
+ "firstname",
1303
+ "lastname",
1304
+ "first",
1305
+ "last",
1306
+ "forename",
1307
+ "surname",
1308
+ "family",
1309
+ "given",
1310
+ "jmeno",
1311
+ "jake",
1312
+ "jaky",
1313
+ "jaka",
1314
+ "jsem",
1315
+ "jsme",
1316
+ "napsal",
1317
+ "napsali",
1318
+ "napsala",
1319
+ "napsane",
1320
+ "pouzil",
1321
+ "pouzili",
1322
+ "prijmeni",
1323
+ "vorname",
1324
+ "nachname",
1325
+ "familienname",
1326
+ "what",
1327
+ "which",
1328
+ "whose",
1329
+ "did",
1330
+ "we",
1331
+ "write",
1332
+ "wrote",
1333
+ "written",
1334
+ "type",
1335
+ "typed",
1336
+ "use",
1337
+ "used",
1338
+ "wie",
1339
+ "welchen",
1340
+ "welche",
1341
+ "welches",
1342
+ "haben",
1343
+ "wir",
1344
+ "geschrieben",
1345
+ "getippt",
1346
+ "quel",
1347
+ "quelle",
1348
+ "nom",
1349
+ "que",
1350
+ "cual",
1351
+ "nombre",
1011
1352
  "write",
1012
1353
  "code",
1013
1354
  "script",
@@ -1034,6 +1375,52 @@ var PERSON_NAME_STOPWORDS = /* @__PURE__ */ new Set([
1034
1375
  "security",
1035
1376
  "instructions",
1036
1377
  "instruction",
1378
+ "google",
1379
+ "form",
1380
+ "forms",
1381
+ "engineering",
1382
+ "leadership",
1383
+ "weekly",
1384
+ "daily",
1385
+ "monthly",
1386
+ "quarterly",
1387
+ "sync",
1388
+ "office",
1389
+ "updates",
1390
+ "update",
1391
+ "meeting",
1392
+ "meetings",
1393
+ "agenda",
1394
+ "minutes",
1395
+ "subject",
1396
+ "calendar",
1397
+ "roadmap",
1398
+ "platform",
1399
+ "product",
1400
+ "design",
1401
+ "operations",
1402
+ "business",
1403
+ "newsletter",
1404
+ "report",
1405
+ "reports",
1406
+ "amazon",
1407
+ "web",
1408
+ "services",
1409
+ "aws",
1410
+ "velka",
1411
+ "transformace",
1412
+ "project",
1413
+ "projekt",
1414
+ "program",
1415
+ "initiative",
1416
+ "iniciativa",
1417
+ "migration",
1418
+ "migrace",
1419
+ "test",
1420
+ "uuid",
1421
+ "fixture",
1422
+ "data",
1423
+ "firma",
1037
1424
  "rules",
1038
1425
  "rule",
1039
1426
  "json",
@@ -1046,10 +1433,22 @@ var PERSON_NAME_STOPWORDS = /* @__PURE__ */ new Set([
1046
1433
  "agentid",
1047
1434
  "risk",
1048
1435
  "score",
1049
- "summary"
1436
+ "summary",
1437
+ "hi",
1438
+ "hello",
1439
+ "hey",
1440
+ "dear",
1441
+ "team",
1442
+ "ahoj",
1443
+ "dobry",
1444
+ "dobryden",
1445
+ "zdravim"
1050
1446
  ]);
1051
1447
  var TECHNICAL_CONTEXT_WORD_REGEX = /\b(?:curl|http|https|import|python|javascript|typescript|sql|nosql|mongo|database|query|script|code|os\.system|eval|exec|node|npm|api|endpoint|regex|json|xml|yaml|bash|powershell)\b/i;
1052
1448
  var TECHNICAL_CONTEXT_SYMBOL_REGEX = /:\/\/|`|\{|\}|\[|\]|\(|\)|;|\$|=>|::|\/\//;
1449
+ var NAME_LABEL_QUESTION_CONTEXT_REGEX = /\b(?:jak(?:e|y|a|ou)|kter(?:e|y|a|ou)|co|what|which|whose|wie|welch(?:e|er|es|en|em)?|quel(?:le|s|les)?|que|cual(?:es)?|wat|welke|jaki|jakie|jaka)\b[\s\S]{0,80}\b(?:jmeno|prijmeni|name|names|namen|nom|nombre|nome|naam|imie|nazwisko|meno)\b[\s\S]{0,96}\b(?:napsal\p{L}*|napsan\p{L}*|psal\p{L}*|pouzil\p{L}*|pouzili\p{L}*|write|wrote|written|type|typed|enter(?:ed)?|use(?:d)?|say|said|geschrieben|getippt|eingetragen|ecrit|escrib\p{L}*|scritt\p{L}*)\b/iu;
1450
+ var NAME_VALUE_ASSIGNMENT_BEFORE_CANDIDATE_REGEX = /(?:[:=]|=>|-|\b(?:is|was|je|jsou|jmenuje|called|named|ist|sind|lautet|est|es)\b)\s*$/iu;
1451
+ var BIRTH_NUMBER_CONTEXT_RE = /\b(?:rodn[eé]\s*(?:č[ií]slo|cislo)|r\.?\s*c\.?|birth\s+number)\b[^0-9]{0,80}(\d{6}(?:\/?\d{3,4})?)\b/giu;
1053
1452
  function hasPhoneContext(text, matchStartIndex, windowSize = 50) {
1054
1453
  const start = Math.max(0, matchStartIndex - windowSize);
1055
1454
  const windowLower = text.slice(start, matchStartIndex).toLowerCase();
@@ -1066,6 +1465,16 @@ function buildContextWindow(source, index, length) {
1066
1465
  function isTechnicalContext(contextWindow) {
1067
1466
  return TECHNICAL_CONTEXT_WORD_REGEX.test(contextWindow) || TECHNICAL_CONTEXT_SYMBOL_REGEX.test(contextWindow);
1068
1467
  }
1468
+ function isNameLabelQuestionContext(contextWindow) {
1469
+ const normalized = normalizePersonWord(contextWindow);
1470
+ if (!normalized.trim()) {
1471
+ return false;
1472
+ }
1473
+ if (!NAME_LABEL_QUESTION_CONTEXT_REGEX.test(normalized)) {
1474
+ return false;
1475
+ }
1476
+ return !NAME_VALUE_ASSIGNMENT_BEFORE_CANDIDATE_REGEX.test(normalized.slice(-32));
1477
+ }
1069
1478
  function isLikelyPersonNameCandidate(candidate, contextWindow) {
1070
1479
  const words = candidate.trim().split(/\s+/);
1071
1480
  if (words.length !== 2) {
@@ -1074,6 +1483,9 @@ function isLikelyPersonNameCandidate(candidate, contextWindow) {
1074
1483
  if (isTechnicalContext(contextWindow)) {
1075
1484
  return false;
1076
1485
  }
1486
+ if (isNameLabelQuestionContext(contextWindow)) {
1487
+ return false;
1488
+ }
1077
1489
  for (const rawWord of words) {
1078
1490
  const normalized = normalizePersonWord(rawWord);
1079
1491
  if (normalized.length < 2) {
@@ -1094,63 +1506,135 @@ var PIIManager = class {
1094
1506
  *
1095
1507
  * Zero-dependency fallback with strict checksum validation for CEE national IDs.
1096
1508
  */
1097
- anonymize(text) {
1509
+ anonymize(text, options) {
1098
1510
  if (!text) return { maskedText: text, mapping: {} };
1099
1511
  try {
1100
1512
  const detections = [];
1101
- const emailRe = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;
1102
- for (const m of text.matchAll(emailRe)) {
1103
- if (m.index == null) continue;
1104
- detections.push({ start: m.index, end: m.index + m[0].length, type: "EMAIL", text: m[0] });
1105
- }
1106
- const ibanRe = /\b[A-Z]{2}\d{2}[A-Z0-9]{11,30}\b/gi;
1107
- for (const m of text.matchAll(ibanRe)) {
1108
- if (m.index == null) continue;
1109
- detections.push({ start: m.index, end: m.index + m[0].length, type: "IBAN", text: m[0] });
1110
- }
1111
- const ccRe = /(?:\b\d[\d -]{10,22}\d\b)/g;
1112
- for (const m of text.matchAll(ccRe)) {
1113
- if (m.index == null) continue;
1114
- const digits = countDigits2(m[0]);
1115
- if (digits < 12 || digits > 19) continue;
1116
- if (!luhnCheck(m[0])) continue;
1117
- detections.push({ start: m.index, end: m.index + m[0].length, type: "CREDIT_CARD", text: m[0] });
1513
+ const loweredText = text.toLowerCase();
1514
+ const resolvedOptions = {
1515
+ pii: options?.pii !== false,
1516
+ secrets: options?.secrets !== false
1517
+ };
1518
+ if (!resolvedOptions.pii && !resolvedOptions.secrets) {
1519
+ return { maskedText: text, mapping: {} };
1118
1520
  }
1119
- const phoneRe = /(?<!\d)(?:\+?\d[\d\s().-]{7,}\d)(?!\d)/g;
1120
- for (const m of text.matchAll(phoneRe)) {
1121
- if (m.index == null) continue;
1122
- const candidate = m[0];
1123
- const digits = countDigits2(candidate);
1124
- if (digits < 9 || digits > 15) continue;
1125
- const isStrongInternational = candidate.startsWith("+") || candidate.startsWith("00");
1126
- if (!isStrongInternational) {
1127
- const hasContext = hasPhoneContext(text, m.index);
1128
- if (!hasContext) continue;
1521
+ if (resolvedOptions.pii) {
1522
+ const emailRe = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;
1523
+ for (const m of text.matchAll(emailRe)) {
1524
+ if (m.index == null) continue;
1525
+ detections.push({ start: m.index, end: m.index + m[0].length, type: "EMAIL", text: m[0] });
1129
1526
  }
1130
- detections.push({ start: m.index, end: m.index + m[0].length, type: "PHONE", text: m[0] });
1131
- }
1132
- const personRe = /(?<!\p{L})\p{Lu}\p{Ll}{2,}\s+\p{Lu}\p{Ll}{2,}(?!\p{L})/gu;
1133
- for (const m of text.matchAll(personRe)) {
1134
- if (m.index == null) continue;
1135
- const candidate = m[0];
1136
- const contextWindow = buildContextWindow(text, m.index, candidate.length);
1137
- if (!isLikelyPersonNameCandidate(candidate, contextWindow)) {
1138
- continue;
1527
+ const ibanRe = /\b[A-Z]{2}\d{2}[A-Z0-9]{11,30}\b/gi;
1528
+ for (const m of text.matchAll(ibanRe)) {
1529
+ if (m.index == null) continue;
1530
+ detections.push({ start: m.index, end: m.index + m[0].length, type: "IBAN", text: m[0] });
1139
1531
  }
1140
- detections.push({ start: m.index, end: m.index + candidate.length, type: "PERSON", text: candidate });
1141
- }
1142
- const nationalIdMatches = detectNationalIdentifiers(text, {
1143
- deadlineMs: defaultScanDeadlineMs,
1144
- allowContextBirthNumberFallback: false
1145
- });
1146
- for (const match of nationalIdMatches) {
1147
- if (match.start < 0 || match.end <= match.start) continue;
1148
- detections.push({
1149
- start: match.start,
1150
- end: match.end,
1151
- type: "NATIONAL_ID",
1152
- text: text.slice(match.start, match.end)
1532
+ const ccRe = /(?:\b\d[\d -]{10,22}\d\b)/g;
1533
+ for (const m of text.matchAll(ccRe)) {
1534
+ if (m.index == null) continue;
1535
+ const digits = countDigits2(m[0]);
1536
+ if (digits < 12 || digits > 19) continue;
1537
+ if (!luhnCheck(m[0])) continue;
1538
+ detections.push({ start: m.index, end: m.index + m[0].length, type: "CREDIT_CARD", text: m[0] });
1539
+ }
1540
+ const phoneRe = /(?<!\d)(?:\+?\d[\d\s().-]{7,}\d)(?!\d)/g;
1541
+ for (const m of text.matchAll(phoneRe)) {
1542
+ if (m.index == null) continue;
1543
+ const candidate = m[0];
1544
+ const digits = countDigits2(candidate);
1545
+ if (digits < 9 || digits > 15) continue;
1546
+ const isStrongInternational = candidate.startsWith("+") || candidate.startsWith("00");
1547
+ if (!isStrongInternational) {
1548
+ const hasContext = hasPhoneContext(text, m.index);
1549
+ if (!hasContext) continue;
1550
+ }
1551
+ detections.push({ start: m.index, end: m.index + m[0].length, type: "PHONE", text: m[0] });
1552
+ }
1553
+ const personRe = /(?<!\p{L})\p{Lu}\p{Ll}{2,}\s+\p{Lu}\p{Ll}{2,}(?!\p{L})/gu;
1554
+ for (const m of text.matchAll(personRe)) {
1555
+ if (m.index == null) continue;
1556
+ const candidate = m[0];
1557
+ const contextWindow = buildContextWindow(text, m.index, candidate.length);
1558
+ if (!isLikelyPersonNameCandidate(candidate, contextWindow)) {
1559
+ continue;
1560
+ }
1561
+ detections.push({ start: m.index, end: m.index + candidate.length, type: "PERSON", text: candidate });
1562
+ }
1563
+ BIRTH_NUMBER_CONTEXT_RE.lastIndex = 0;
1564
+ for (const match of text.matchAll(BIRTH_NUMBER_CONTEXT_RE)) {
1565
+ if (match.index == null) continue;
1566
+ const value = match[1] ?? "";
1567
+ if (!/^\d{6}(?:\/?\d{3,4})?$/.test(value)) continue;
1568
+ const localIndex = match[0].lastIndexOf(value);
1569
+ const start = match.index + Math.max(0, localIndex);
1570
+ detections.push({
1571
+ start,
1572
+ end: start + value.length,
1573
+ type: "BIRTH_NUMBER",
1574
+ text: value
1575
+ });
1576
+ }
1577
+ const nationalIdMatches = detectNationalIdentifiers(text, {
1578
+ deadlineMs: defaultScanDeadlineMs,
1579
+ allowContextBirthNumberFallback: false
1153
1580
  });
1581
+ for (const match of nationalIdMatches) {
1582
+ if (match.start < 0 || match.end <= match.start) continue;
1583
+ detections.push({
1584
+ start: match.start,
1585
+ end: match.end,
1586
+ type: "NATIONAL_ID",
1587
+ text: text.slice(match.start, match.end)
1588
+ });
1589
+ }
1590
+ }
1591
+ if (resolvedOptions.secrets) {
1592
+ BASIC_AUTH_PASSWORD_RE.lastIndex = 0;
1593
+ for (const match of text.matchAll(BASIC_AUTH_PASSWORD_RE)) {
1594
+ if (match.index == null) continue;
1595
+ const password = match[1] ?? "";
1596
+ if (!password) continue;
1597
+ const localIndex = match[0].lastIndexOf(password);
1598
+ const start = match.index + Math.max(0, localIndex);
1599
+ detections.push({
1600
+ start,
1601
+ end: start + password.length,
1602
+ type: "BASIC_AUTH_PASSWORD",
1603
+ text: password
1604
+ });
1605
+ }
1606
+ DISCORD_WEBHOOK_TOKEN_RE.lastIndex = 0;
1607
+ for (const match of text.matchAll(DISCORD_WEBHOOK_TOKEN_RE)) {
1608
+ if (match.index == null) continue;
1609
+ const token = match[1] ?? "";
1610
+ if (!token) continue;
1611
+ const localIndex = match[0].lastIndexOf(token);
1612
+ const start = match.index + Math.max(0, localIndex);
1613
+ detections.push({
1614
+ start,
1615
+ end: start + token.length,
1616
+ type: "DISCORD_WEBHOOK_TOKEN",
1617
+ text: token
1618
+ });
1619
+ }
1620
+ for (const matcher of sdkSecretMatchers) {
1621
+ if (matcher.id === "discord_webhook_url") {
1622
+ continue;
1623
+ }
1624
+ if (matcher.prefilterTermsLower.length > 0 && !matcher.prefilterTermsLower.some((term) => loweredText.includes(term))) {
1625
+ continue;
1626
+ }
1627
+ matcher.scanRegex.lastIndex = 0;
1628
+ for (const match of text.matchAll(matcher.scanRegex)) {
1629
+ if (match.index == null) continue;
1630
+ detections.push({
1631
+ start: match.index,
1632
+ end: match.index + match[0].length,
1633
+ type: matcher.placeholderType,
1634
+ text: match[0]
1635
+ });
1636
+ }
1637
+ }
1154
1638
  }
1155
1639
  const kept = normalizeDetections(text, detections);
1156
1640
  if (!kept.length) return { maskedText: text, mapping: {} };
@@ -1196,6 +1680,8 @@ var DEFAULT_FAIL_OPEN_CONFIG = {
1196
1680
  inject_transparency_metadata: false,
1197
1681
  block_pii_leakage: false,
1198
1682
  enable_sdk_pii_masking: false,
1683
+ block_secret_leakage: false,
1684
+ enable_sdk_secret_masking: false,
1199
1685
  block_db_access: false,
1200
1686
  block_code_execution: false,
1201
1687
  block_toxicity: false
@@ -1237,11 +1723,11 @@ function detectCapabilityViolation(text, config) {
1237
1723
  }
1238
1724
  return null;
1239
1725
  }
1240
- function redactPiiStrict(pii, text) {
1726
+ function redactPiiStrict(pii, text, options) {
1241
1727
  if (!text) {
1242
1728
  return { redactedText: text, changed: false };
1243
1729
  }
1244
- const masked = pii.anonymize(text);
1730
+ const masked = pii.anonymize(text, options);
1245
1731
  let redactedText = masked.maskedText;
1246
1732
  const placeholders = Object.keys(masked.mapping).sort((a, b) => b.length - a.length);
1247
1733
  for (const placeholder of placeholders) {
@@ -1270,7 +1756,7 @@ var LocalSecurityEnforcer = class {
1270
1756
  `AgentID: Security policy blocked (${violationType})`
1271
1757
  );
1272
1758
  }
1273
- if (!config.block_pii_leakage) {
1759
+ if (!config.block_pii_leakage && !config.block_secret_leakage) {
1274
1760
  return {
1275
1761
  sanitizedInput: input,
1276
1762
  events: []
@@ -1280,10 +1766,13 @@ var LocalSecurityEnforcer = class {
1280
1766
  throw new SecurityPolicyViolationError(
1281
1767
  "PII_LEAKAGE_STRICT",
1282
1768
  "BLOCKED",
1283
- "AgentID: Streaming is not supported when Strict PII Mode is enabled. Please disable streaming or adjust security settings."
1769
+ "AgentID: Streaming is not supported when strict masking/blocking mode is enabled. Please disable streaming or adjust security settings."
1284
1770
  );
1285
1771
  }
1286
- const strictRedaction = redactPiiStrict(this.pii, input);
1772
+ const strictRedaction = redactPiiStrict(this.pii, input, {
1773
+ pii: config.block_pii_leakage,
1774
+ secrets: config.block_secret_leakage
1775
+ });
1287
1776
  return {
1288
1777
  sanitizedInput: strictRedaction.redactedText,
1289
1778
  events: strictRedaction.changed ? [
@@ -1409,6 +1898,16 @@ function normalizeCapabilityConfig(payload) {
1409
1898
  "enable_sdk_pii_masking",
1410
1899
  false
1411
1900
  ),
1901
+ block_secret_leakage: readOptionalBooleanField(
1902
+ body,
1903
+ "block_secret_leakage",
1904
+ false
1905
+ ),
1906
+ enable_sdk_secret_masking: readOptionalBooleanField(
1907
+ body,
1908
+ "enable_sdk_secret_masking",
1909
+ false
1910
+ ),
1412
1911
  block_db_access: readBooleanField(body, "block_db_access", "block_db"),
1413
1912
  block_code_execution: readBooleanField(
1414
1913
  body,
@@ -2069,14 +2568,14 @@ async function reportSecurityEvent(options) {
2069
2568
  const inputValue = options.storePii ? snippet : snippetHash;
2070
2569
  const eventId = createEventId(options.eventId ?? options.clientEventId);
2071
2570
  const metadata = {
2571
+ ...options.telemetryMetadata ?? {},
2072
2572
  source: options.source,
2073
2573
  detector: options.detector,
2074
2574
  trigger_rule: options.triggerRule,
2075
2575
  language: options.language,
2076
2576
  ai_scan_status: options.aiStatus ?? null,
2077
2577
  reason: options.reason ?? null,
2078
- client_event_id: eventId,
2079
- ...options.telemetryMetadata ?? {}
2578
+ client_event_id: eventId
2080
2579
  };
2081
2580
  if (options.storePii) {
2082
2581
  metadata.snippet = snippet;
@@ -2248,9 +2747,18 @@ var INGEST_MAX_ATTEMPTS = 3;
2248
2747
  var INGEST_RETRY_DELAYS_MS = [250, 500];
2249
2748
  var GUARD_VERDICT_CACHE_TTL_MS = 0;
2250
2749
  var MAX_INGEST_TEXT_CHARS = 32e3;
2750
+ var OPENAI_TELEMETRY_FIELD = "agentid_telemetry";
2251
2751
  function normalizeBaseUrl3(baseUrl) {
2252
2752
  return baseUrl.replace(/\/+$/, "");
2253
2753
  }
2754
+ function firstNonEmptyString(...values) {
2755
+ for (const value of values) {
2756
+ if (typeof value === "string" && value.trim().length > 0) {
2757
+ return value.trim();
2758
+ }
2759
+ }
2760
+ return void 0;
2761
+ }
2254
2762
  function isAbortSignalLike(value) {
2255
2763
  if (!value || typeof value !== "object") return false;
2256
2764
  const candidate = value;
@@ -2412,6 +2920,424 @@ function createCorrelationId(seed) {
2412
2920
  }
2413
2921
  return createPseudoUuidV42();
2414
2922
  }
2923
+ function getObjectString(value, ...keys) {
2924
+ for (const key of keys) {
2925
+ const candidate = value?.[key];
2926
+ if (typeof candidate === "string" && candidate.trim().length > 0) {
2927
+ return candidate.trim();
2928
+ }
2929
+ }
2930
+ return void 0;
2931
+ }
2932
+ function getObjectNumber(value, ...keys) {
2933
+ for (const key of keys) {
2934
+ const candidate = value?.[key];
2935
+ if (typeof candidate === "number" && Number.isFinite(candidate)) {
2936
+ return candidate;
2937
+ }
2938
+ if (typeof candidate === "string" && candidate.trim().length > 0) {
2939
+ const parsed = Number(candidate);
2940
+ if (Number.isFinite(parsed)) {
2941
+ return parsed;
2942
+ }
2943
+ }
2944
+ }
2945
+ return void 0;
2946
+ }
2947
+ function normalizeTelemetryString(value) {
2948
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
2949
+ }
2950
+ function normalizeTelemetryCategory(value) {
2951
+ const normalized = normalizeTelemetryString(value);
2952
+ if (!normalized) return void 0;
2953
+ return normalized.toLowerCase().replace(/[\s-]+/g, "_");
2954
+ }
2955
+ function toSnakeToken(value) {
2956
+ return value.trim().replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").replace(/^_+|_+$/g, "").replace(/_+/g, "_").toLowerCase();
2957
+ }
2958
+ function hasUsageSignals(value) {
2959
+ if (!value) return false;
2960
+ for (const entry of Object.values(value)) {
2961
+ if (typeof entry === "number" && Number.isFinite(entry) && entry > 0) {
2962
+ return true;
2963
+ }
2964
+ if (typeof entry === "string" && entry.trim().length > 0) {
2965
+ const parsed = Number(entry);
2966
+ if (Number.isFinite(parsed) && parsed > 0) {
2967
+ return true;
2968
+ }
2969
+ }
2970
+ }
2971
+ return false;
2972
+ }
2973
+ function truncatePromptPreflightPreview(value, maxChars = 280) {
2974
+ const normalized = value.trim();
2975
+ if (normalized.length <= maxChars) {
2976
+ return normalized;
2977
+ }
2978
+ return `${normalized.slice(0, Math.max(0, maxChars - 1)).trimEnd()}\u2026`;
2979
+ }
2980
+ function formatPromptPreflightReason(reason) {
2981
+ const normalized = normalizeTelemetryString(reason);
2982
+ if (!normalized) {
2983
+ return void 0;
2984
+ }
2985
+ return normalized.replace(/[_-]+/g, " ");
2986
+ }
2987
+ function summarizePromptPreflightResult(params) {
2988
+ const reason = formatPromptPreflightReason(
2989
+ params.localFallbackApplied ? params.localFallbackReason ?? void 0 : params.verdict.reason
2990
+ ) ?? "policy evaluation";
2991
+ if (!params.verdict.allowed && !params.localFallbackApplied) {
2992
+ return `Blocked the prompt before model execution because ${reason}.`;
2993
+ }
2994
+ if (params.localFallbackApplied) {
2995
+ return `Guard preflight degraded, so the SDK applied local fallback checks before model execution (${reason}).`;
2996
+ }
2997
+ if (params.verdict.shadow_mode && params.verdict.shadow_blocked) {
2998
+ return "Evaluated the prompt in shadow mode before model execution; shadow policy would have blocked it.";
2999
+ }
3000
+ if (params.verdict.simulated_decision === "masked" || params.verdict.detected_pii) {
3001
+ return "Evaluated the prompt before model execution and masked sensitive content where needed.";
3002
+ }
3003
+ return "Evaluated the prompt and attachments against guardrails before model execution.";
3004
+ }
3005
+ function buildPromptPreflightTelemetry(params) {
3006
+ const baseTelemetry = createAgentIdTelemetryContext(params.telemetry);
3007
+ const baseStepName = firstNonEmptyString(
3008
+ baseTelemetry?.workflow_step_name,
3009
+ baseTelemetry?.workflowStepName
3010
+ );
3011
+ const stepName = baseStepName ? `${toSnakeToken(baseStepName)}_preflight` : "prompt_preflight";
3012
+ const summary = summarizePromptPreflightResult({
3013
+ verdict: params.verdict,
3014
+ localFallbackApplied: params.local_fallback_applied,
3015
+ localFallbackReason: params.local_fallback_reason
3016
+ });
3017
+ return mergeTelemetryContexts(baseTelemetry, {
3018
+ workflow_step_id: createAgentIdCorrelationId(),
3019
+ workflow_step_name: stepName,
3020
+ event_title: "Prompt Preflight Evaluated",
3021
+ event_category: "guard",
3022
+ event_subtype: "prompt_preflight_evaluated",
3023
+ event_status: !params.verdict.allowed && !params.local_fallback_applied ? "blocked" : "completed",
3024
+ step_summary: summary,
3025
+ input_preview: truncatePromptPreflightPreview(params.input),
3026
+ output_preview: summary,
3027
+ runtime_surface: params.runtime_surface ?? "openai_sdk_guard",
3028
+ guard_event_id: params.guard_event_id ?? void 0,
3029
+ guard_latency_ms: params.guard_latency_ms ?? void 0,
3030
+ preflight_for_client_event_id: params.preflight_for_client_event_id,
3031
+ preflight_logged_via_sdk: true,
3032
+ lifecycle_status: "preflight_only"
3033
+ });
3034
+ }
3035
+ function inferOperationCategory(telemetry, eventType) {
3036
+ const explicitCategory = normalizeTelemetryCategory(
3037
+ telemetry?.event_category ?? telemetry?.eventCategory
3038
+ );
3039
+ if (explicitCategory === "ai" || explicitCategory === "llm" || explicitCategory === "inference") {
3040
+ return "ai";
3041
+ }
3042
+ if (explicitCategory === "guard" || explicitCategory === "security") {
3043
+ return "guard";
3044
+ }
3045
+ if (explicitCategory === "tool") return "tool";
3046
+ if (explicitCategory === "delivery" || explicitCategory === "send") return "delivery";
3047
+ if (explicitCategory === "inbox" || explicitCategory === "reply") return "inbox";
3048
+ if (explicitCategory === "workflow" || explicitCategory === "agent") return "workflow";
3049
+ if (explicitCategory === "compliance" || explicitCategory === "transparency") {
3050
+ return "compliance";
3051
+ }
3052
+ if (explicitCategory === "operational" || explicitCategory === "ops") {
3053
+ return "operational";
3054
+ }
3055
+ const haystack = [
3056
+ eventType,
3057
+ telemetry?.event_subtype,
3058
+ telemetry?.eventSubtype,
3059
+ telemetry?.tool_name,
3060
+ telemetry?.toolName,
3061
+ telemetry?.tool_target_type,
3062
+ telemetry?.toolTargetType,
3063
+ telemetry?.workflow_name,
3064
+ telemetry?.workflowName,
3065
+ telemetry?.workflow_step_name,
3066
+ telemetry?.workflowStepName,
3067
+ getObjectString(telemetry, "operation_family", "domain")
3068
+ ].filter((entry) => typeof entry === "string" && entry.trim().length > 0).join(" ").replace(/[_./-]+/g, " ").toLowerCase();
3069
+ if (/\b(llm|ai|inference|completion|summary|classification|draft)\b/.test(haystack)) {
3070
+ return "ai";
3071
+ }
3072
+ if (/\b(guard|security|policy|pii|prompt[_ ]?injection|review)\b/.test(haystack)) {
3073
+ return "guard";
3074
+ }
3075
+ if (/\b(reply|inbox|inbound|received|bounce|opened|followup)\b/.test(haystack)) {
3076
+ return "inbox";
3077
+ }
3078
+ if (/\b(email|mail|send|delivery|delivered|slack|sms|webhook|notification)\b/.test(haystack)) {
3079
+ return "delivery";
3080
+ }
3081
+ if (/\b(workflow|step|run|agent)\b/.test(haystack)) {
3082
+ return "workflow";
3083
+ }
3084
+ if (/\b(compliance|transparency|audit|evidence)\b/.test(haystack)) {
3085
+ return "compliance";
3086
+ }
3087
+ if (/\b(tool|lookup|search|query|retrieve|fetch|crm|invoice|payment|ledger|expense|payroll|tax|finance|cv|resume|candidate|applicant|recruit|interview|screen|document|file|attachment|extract|parse|ocr|classify|sync|import|export|record|database|sql|shell|terminal|script)\b/.test(
3088
+ haystack
3089
+ )) {
3090
+ return "tool";
3091
+ }
3092
+ return "operational";
3093
+ }
3094
+ function inferOperationStatus(params) {
3095
+ const explicitStatus = normalizeTelemetryString(params.eventStatus)?.toLowerCase();
3096
+ if (explicitStatus === "started" || explicitStatus === "completed" || explicitStatus === "failed") {
3097
+ return explicitStatus;
3098
+ }
3099
+ if (explicitStatus === "blocked" || explicitStatus === "skipped") {
3100
+ return explicitStatus;
3101
+ }
3102
+ const normalizedEventType = normalizeTelemetryString(params.eventType)?.toLowerCase();
3103
+ if (normalizedEventType === "start") return "started";
3104
+ if (normalizedEventType === "error") return "failed";
3105
+ if (normalizedEventType === "security_block") return "blocked";
3106
+ if (normalizedEventType === "human_override") return "completed";
3107
+ if (normalizedEventType === "complete") return "completed";
3108
+ return params.severity === "error" ? "failed" : "completed";
3109
+ }
3110
+ function deriveOperationEventType(params) {
3111
+ const explicit = normalizeTelemetryString(params.explicitEventType);
3112
+ if (explicit) {
3113
+ return explicit;
3114
+ }
3115
+ if (params.status === "started") return "start";
3116
+ if (params.status === "failed") return "error";
3117
+ if (params.status === "blocked") {
3118
+ return params.category === "guard" ? "security_block" : "error";
3119
+ }
3120
+ return "complete";
3121
+ }
3122
+ function deriveSubtypeBase(telemetry) {
3123
+ const toolName = normalizeTelemetryString(telemetry?.tool_name ?? telemetry?.toolName);
3124
+ if (toolName) {
3125
+ const tokens = toSnakeToken(toolName).split("_").filter(Boolean);
3126
+ if (tokens.length > 1 && ["workflow", "agent", "operation", "ops", "hr", "finance", "compliance"].includes(tokens[0])) {
3127
+ return tokens.slice(1).join("_");
3128
+ }
3129
+ return tokens.join("_");
3130
+ }
3131
+ const workflowName = normalizeTelemetryString(
3132
+ telemetry?.workflow_step_name ?? telemetry?.workflowStepName ?? telemetry?.workflow_name ?? telemetry?.workflowName
3133
+ );
3134
+ if (workflowName) {
3135
+ return toSnakeToken(workflowName);
3136
+ }
3137
+ return void 0;
3138
+ }
3139
+ function deriveOperationSubtype(params) {
3140
+ const explicitSubtype = normalizeTelemetryString(params.explicitSubtype);
3141
+ if (explicitSubtype) {
3142
+ return toSnakeToken(explicitSubtype);
3143
+ }
3144
+ const base = deriveSubtypeBase(params.telemetry);
3145
+ const suffix = params.status === "started" ? "started" : params.status === "failed" ? "failed" : params.status === "blocked" ? "blocked" : params.status === "skipped" ? "skipped" : "completed";
3146
+ if (base) {
3147
+ return `${base}_${suffix}`;
3148
+ }
3149
+ if (params.eventType === "start") return `${params.category}_started`;
3150
+ if (params.eventType === "error") return `${params.category}_failed`;
3151
+ if (params.eventType === "security_block") return `${params.category}_blocked`;
3152
+ return `${params.category}_completed`;
3153
+ }
3154
+ function inferOperationSeverity(params) {
3155
+ if (params.explicitSeverity) {
3156
+ return params.explicitSeverity;
3157
+ }
3158
+ if (params.status === "failed" || params.status === "blocked") {
3159
+ return "error";
3160
+ }
3161
+ if (params.status === "skipped") {
3162
+ return "warning";
3163
+ }
3164
+ return "info";
3165
+ }
3166
+ function createAgentIdCorrelationId(seed) {
3167
+ return createCorrelationId(seed);
3168
+ }
3169
+ function createAgentIdTelemetryContext(value) {
3170
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
3171
+ return void 0;
3172
+ }
3173
+ const raw = { ...value };
3174
+ const normalized = {};
3175
+ const assignString = (key, ...aliases) => {
3176
+ const next = getObjectString(raw, key, ...aliases);
3177
+ if (next) {
3178
+ normalized[key] = next;
3179
+ }
3180
+ };
3181
+ const assignNumber = (key, ...aliases) => {
3182
+ const next = getObjectNumber(raw, key, ...aliases);
3183
+ if (typeof next === "number") {
3184
+ normalized[key] = next;
3185
+ }
3186
+ };
3187
+ assignString("workflow_id", "workflowId");
3188
+ assignString("workflow_run_id", "workflowRunId");
3189
+ assignString("workflow_step_id", "workflowStepId");
3190
+ assignString("workflow_name", "workflowName");
3191
+ assignString("workflow_step_name", "workflowStepName");
3192
+ assignNumber("workflow_step_index", "workflowStepIndex");
3193
+ assignString("parent_event_id", "parentEventId");
3194
+ assignString("tool_name", "toolName");
3195
+ assignString("tool_target", "toolTarget");
3196
+ assignString("tool_target_type", "toolTargetType");
3197
+ assignString("event_title", "eventTitle");
3198
+ assignString("event_status", "eventStatus");
3199
+ assignString("event_category", "eventCategory");
3200
+ assignString("event_subtype", "eventSubtype");
3201
+ const consumedKeys = /* @__PURE__ */ new Set([
3202
+ "workflow_id",
3203
+ "workflowId",
3204
+ "workflow_run_id",
3205
+ "workflowRunId",
3206
+ "workflow_step_id",
3207
+ "workflowStepId",
3208
+ "workflow_name",
3209
+ "workflowName",
3210
+ "workflow_step_name",
3211
+ "workflowStepName",
3212
+ "workflow_step_index",
3213
+ "workflowStepIndex",
3214
+ "parent_event_id",
3215
+ "parentEventId",
3216
+ "tool_name",
3217
+ "toolName",
3218
+ "tool_target",
3219
+ "toolTarget",
3220
+ "tool_target_type",
3221
+ "toolTargetType",
3222
+ "event_title",
3223
+ "eventTitle",
3224
+ "event_status",
3225
+ "eventStatus",
3226
+ "event_category",
3227
+ "eventCategory",
3228
+ "event_subtype",
3229
+ "eventSubtype"
3230
+ ]);
3231
+ for (const [key, entry] of Object.entries(raw)) {
3232
+ if (consumedKeys.has(key) || entry === void 0) {
3233
+ continue;
3234
+ }
3235
+ if (typeof entry === "string") {
3236
+ if (entry.trim().length > 0) {
3237
+ normalized[key] = entry.trim();
3238
+ }
3239
+ continue;
3240
+ }
3241
+ normalized[key] = entry;
3242
+ }
3243
+ if (typeof normalized.workflow_id !== "string" && typeof normalized.workflow_run_id === "string") {
3244
+ normalized.workflow_id = normalized.workflow_run_id;
3245
+ }
3246
+ return Object.keys(normalized).length > 0 ? normalized : void 0;
3247
+ }
3248
+ function createAgentIdOperationLog(params) {
3249
+ const telemetry = createAgentIdTelemetryContext(params.telemetry);
3250
+ const category = inferOperationCategory(
3251
+ createAgentIdTelemetryContext({
3252
+ ...telemetry ?? {},
3253
+ event_category: params.event_category ?? telemetry?.event_category
3254
+ }),
3255
+ params.event_type
3256
+ );
3257
+ const status = inferOperationStatus({
3258
+ eventStatus: normalizeTelemetryString(params.event_status) ?? normalizeTelemetryString(telemetry?.event_status ?? telemetry?.eventStatus),
3259
+ eventType: params.event_type,
3260
+ severity: params.severity
3261
+ });
3262
+ const eventType = deriveOperationEventType({
3263
+ explicitEventType: params.event_type,
3264
+ status,
3265
+ category
3266
+ });
3267
+ const subtype = deriveOperationSubtype({
3268
+ explicitSubtype: normalizeTelemetryString(params.event_subtype) ?? normalizeTelemetryString(telemetry?.event_subtype ?? telemetry?.eventSubtype),
3269
+ telemetry,
3270
+ category,
3271
+ status,
3272
+ eventType
3273
+ });
3274
+ const severity = inferOperationSeverity({
3275
+ explicitSeverity: params.severity,
3276
+ status
3277
+ });
3278
+ const usage = params.usage;
3279
+ const clientEventId = normalizeTelemetryString(params.client_event_id) ?? normalizeTelemetryString(telemetry?.client_event_id);
3280
+ const modelUsed = category === "ai" || hasUsageSignals(usage) || typeof params.model === "string" && params.model.trim().length > 0 && params.model.trim().toLowerCase() !== "not_applicable";
3281
+ const metadata = {
3282
+ ...params.metadata ?? {},
3283
+ ...telemetry ?? {},
3284
+ event_category: category,
3285
+ event_subtype: subtype,
3286
+ event_status: status,
3287
+ status,
3288
+ model_used: modelUsed,
3289
+ spend_bearing: category === "ai" && hasUsageSignals(usage)
3290
+ };
3291
+ if (clientEventId && typeof metadata.client_event_id !== "string") {
3292
+ metadata.client_event_id = clientEventId;
3293
+ }
3294
+ return {
3295
+ event_id: normalizeTelemetryString(params.event_id) ?? createEventId2(),
3296
+ system_id: params.system_id,
3297
+ user_id: params.user_id,
3298
+ request_identity: params.request_identity,
3299
+ input: params.input ?? "",
3300
+ output: params.output ?? "",
3301
+ model: normalizeTelemetryString(params.model) ?? "not_applicable",
3302
+ usage,
3303
+ tokens: params.tokens,
3304
+ latency: params.latency,
3305
+ metadata,
3306
+ event_type: eventType,
3307
+ severity,
3308
+ timestamp: params.timestamp,
3309
+ client_capabilities: params.client_capabilities
3310
+ };
3311
+ }
3312
+ function asTelemetryContext(value) {
3313
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
3314
+ return void 0;
3315
+ }
3316
+ return createAgentIdTelemetryContext(value);
3317
+ }
3318
+ function mergeTelemetryContexts(...contexts) {
3319
+ const merged = {};
3320
+ let hasValues = false;
3321
+ for (const context of contexts) {
3322
+ if (!context) {
3323
+ continue;
3324
+ }
3325
+ Object.assign(merged, createAgentIdTelemetryContext(context));
3326
+ hasValues = true;
3327
+ }
3328
+ return hasValues ? createAgentIdTelemetryContext(merged) : void 0;
3329
+ }
3330
+ function extractRequestTelemetryContext(requestBody) {
3331
+ return asTelemetryContext(requestBody[OPENAI_TELEMETRY_FIELD]);
3332
+ }
3333
+ function stripRequestTelemetryContext(requestBody) {
3334
+ if (!Object.prototype.hasOwnProperty.call(requestBody, OPENAI_TELEMETRY_FIELD)) {
3335
+ return requestBody;
3336
+ }
3337
+ const nextRequestBody = { ...requestBody };
3338
+ delete nextRequestBody[OPENAI_TELEMETRY_FIELD];
3339
+ return nextRequestBody;
3340
+ }
2415
3341
  async function waitForRetry(attemptIndex) {
2416
3342
  const delay = GUARD_RETRY_DELAYS_MS[attemptIndex];
2417
3343
  if (!delay) return;
@@ -2591,6 +3517,61 @@ function createStreamingPlaceholderRewriter(piiManager, mapping) {
2591
3517
  }
2592
3518
  };
2593
3519
  }
3520
+ var TYPED_PLACEHOLDER_RE = /<[A-Z][A-Z0-9_]*_\d+>/g;
3521
+ function derivePlaceholderMappingFromTransform(source, transformed) {
3522
+ if (!source || !transformed || source === transformed) {
3523
+ return {};
3524
+ }
3525
+ const placeholders = [...transformed.matchAll(TYPED_PLACEHOLDER_RE)].map((match) => ({
3526
+ token: match[0],
3527
+ start: match.index ?? 0,
3528
+ end: (match.index ?? 0) + match[0].length
3529
+ }));
3530
+ if (placeholders.length === 0) {
3531
+ return {};
3532
+ }
3533
+ const mapping = {};
3534
+ let sourceCursor = 0;
3535
+ let transformedCursor = 0;
3536
+ for (const placeholder of placeholders) {
3537
+ const literalBefore = transformed.slice(transformedCursor, placeholder.start);
3538
+ if (literalBefore) {
3539
+ const literalIndex = source.indexOf(literalBefore, sourceCursor);
3540
+ if (literalIndex < 0) {
3541
+ return {};
3542
+ }
3543
+ sourceCursor = literalIndex + literalBefore.length;
3544
+ }
3545
+ const nextPlaceholderStart = placeholders.find((candidate) => candidate.start > placeholder.start)?.start ?? transformed.length;
3546
+ const literalAfter = transformed.slice(placeholder.end, nextPlaceholderStart);
3547
+ const nextLiteralIndex = literalAfter ? source.indexOf(literalAfter, sourceCursor) : nextPlaceholderStart >= transformed.length ? source.length : sourceCursor;
3548
+ if (nextLiteralIndex < sourceCursor) {
3549
+ return {};
3550
+ }
3551
+ const originalValue = source.slice(sourceCursor, nextLiteralIndex);
3552
+ if (originalValue.length > 0 && typeof mapping[placeholder.token] !== "string") {
3553
+ mapping[placeholder.token] = originalValue;
3554
+ }
3555
+ sourceCursor = nextLiteralIndex;
3556
+ transformedCursor = placeholder.end;
3557
+ }
3558
+ return mapping;
3559
+ }
3560
+ function mergePiiMappings(primary, fallback) {
3561
+ const merged = { ...primary };
3562
+ for (const [placeholder, value] of Object.entries(fallback)) {
3563
+ if (typeof merged[placeholder] !== "string" && typeof value === "string") {
3564
+ merged[placeholder] = value;
3565
+ }
3566
+ }
3567
+ return merged;
3568
+ }
3569
+ function textContainsMappingPlaceholder(text, mapping) {
3570
+ if (!text || !mapping) {
3571
+ return false;
3572
+ }
3573
+ return Object.keys(mapping).some((placeholder) => placeholder.length > 0 && text.includes(placeholder));
3574
+ }
2594
3575
  var SecurityBlockError = class extends Error {
2595
3576
  constructor(reason = "guard_denied") {
2596
3577
  super(`AgentID: Security Blocked (${reason})`);
@@ -2615,6 +3596,7 @@ var AgentID = class {
2615
3596
  this.apiKey = resolveConfiguredApiKey(config.apiKey);
2616
3597
  this.baseUrl = normalizeBaseUrl3(config.baseUrl ?? "https://app.getagentid.com/api/v1");
2617
3598
  this.configuredPiiMasking = typeof config.piiMasking === "boolean" ? config.piiMasking : null;
3599
+ this.configuredSecretMasking = typeof config.secretMasking === "boolean" ? config.secretMasking : null;
2618
3600
  this.checkInjection = config.checkInjection !== false;
2619
3601
  this.clientFastFail = config.clientFastFail === true || config.client_fast_fail === true;
2620
3602
  this.aiScanEnabled = config.aiScanEnabled !== false;
@@ -2636,11 +3618,26 @@ var AgentID = class {
2636
3618
  get piiMasking() {
2637
3619
  return this.configuredPiiMasking ?? void 0;
2638
3620
  }
3621
+ get secretMasking() {
3622
+ return this.configuredSecretMasking ?? void 0;
3623
+ }
2639
3624
  resolveEffectivePiiMasking(config) {
3625
+ if (config?.enable_sdk_pii_masking === true) {
3626
+ return true;
3627
+ }
2640
3628
  if (this.configuredPiiMasking !== null) {
2641
3629
  return this.configuredPiiMasking;
2642
3630
  }
2643
- return config?.enable_sdk_pii_masking === true;
3631
+ return false;
3632
+ }
3633
+ resolveEffectiveSecretMasking(config) {
3634
+ if (config?.enable_sdk_secret_masking === true || config?.enable_sdk_pii_masking === true) {
3635
+ return true;
3636
+ }
3637
+ if (this.configuredSecretMasking !== null) {
3638
+ return this.configuredSecretMasking;
3639
+ }
3640
+ return false;
2644
3641
  }
2645
3642
  getEffectivePiiMasking(options) {
2646
3643
  return this.resolveEffectivePiiMasking(this.getCachedCapabilityConfig(options));
@@ -2648,6 +3645,9 @@ var AgentID = class {
2648
3645
  getEffectivePiiMaskingForConfig(capabilityConfig) {
2649
3646
  return this.resolveEffectivePiiMasking(capabilityConfig);
2650
3647
  }
3648
+ getEffectiveSecretMaskingForConfig(capabilityConfig) {
3649
+ return this.resolveEffectiveSecretMasking(capabilityConfig);
3650
+ }
2651
3651
  buildClientCapabilities(framework = "js_sdk", hasFeedbackHandler = false, capabilityConfig) {
2652
3652
  return {
2653
3653
  capabilities: {
@@ -2655,6 +3655,9 @@ var AgentID = class {
2655
3655
  pii_masking_enabled: this.resolveEffectivePiiMasking(
2656
3656
  capabilityConfig ?? this.getCachedCapabilityConfig()
2657
3657
  ),
3658
+ secret_masking_enabled: this.resolveEffectiveSecretMasking(
3659
+ capabilityConfig ?? this.getCachedCapabilityConfig()
3660
+ ),
2658
3661
  framework
2659
3662
  }
2660
3663
  };
@@ -2794,10 +3797,13 @@ var AgentID = class {
2794
3797
  systemId: params.systemId,
2795
3798
  eventId: params.clientEventId,
2796
3799
  clientEventId: params.clientEventId,
2797
- telemetryMetadata: buildSdkTimingMetadata({
2798
- sdkConfigFetchMs: params.sdkConfigFetchMs,
2799
- sdkConfigVersion: params.capabilityConfig.version
2800
- })
3800
+ telemetryMetadata: mergeTelemetryContexts(
3801
+ params.telemetryMetadata,
3802
+ buildSdkTimingMetadata({
3803
+ sdkConfigFetchMs: params.sdkConfigFetchMs,
3804
+ sdkConfigVersion: params.capabilityConfig.version
3805
+ })
3806
+ )
2801
3807
  });
2802
3808
  }
2803
3809
  try {
@@ -2814,7 +3820,8 @@ var AgentID = class {
2814
3820
  actionTaken: event.actionTaken,
2815
3821
  apiKey: params.apiKey,
2816
3822
  sdkConfigFetchMs: params.sdkConfigFetchMs,
2817
- sdkLocalScanMs
3823
+ sdkLocalScanMs,
3824
+ telemetryMetadata: params.telemetryMetadata
2818
3825
  });
2819
3826
  }
2820
3827
  return {
@@ -2829,7 +3836,8 @@ var AgentID = class {
2829
3836
  actionTaken: error.actionTaken,
2830
3837
  apiKey: params.apiKey,
2831
3838
  sdkConfigFetchMs: params.sdkConfigFetchMs,
2832
- sdkLocalScanMs: Math.max(0, Date.now() - localScanStartedAt)
3839
+ sdkLocalScanMs: Math.max(0, Date.now() - localScanStartedAt),
3840
+ telemetryMetadata: params.telemetryMetadata
2833
3841
  });
2834
3842
  }
2835
3843
  throw error;
@@ -2843,7 +3851,7 @@ var AgentID = class {
2843
3851
  );
2844
3852
  let sanitizedInput = params.input;
2845
3853
  let sdkLocalScanMs = 0;
2846
- if (this.configuredPiiMasking === null) {
3854
+ if (this.configuredPiiMasking === null || this.configuredSecretMasking === null) {
2847
3855
  const refreshed = await this.refreshCapabilityConfigBeforeClientControl({
2848
3856
  capabilityConfig,
2849
3857
  sdkConfigFetchMs,
@@ -2854,8 +3862,12 @@ var AgentID = class {
2854
3862
  }
2855
3863
  if (!this.clientFastFail) {
2856
3864
  const effectivePiiMasking2 = this.resolveEffectivePiiMasking(capabilityConfig);
2857
- if (!capabilityConfig.block_pii_leakage && effectivePiiMasking2) {
2858
- const masked = this.pii.anonymize(sanitizedInput);
3865
+ const effectiveSecretMasking2 = this.resolveEffectiveSecretMasking(capabilityConfig);
3866
+ if (!capabilityConfig.block_pii_leakage && effectivePiiMasking2 || !capabilityConfig.block_secret_leakage && effectiveSecretMasking2) {
3867
+ const masked = this.pii.anonymize(sanitizedInput, {
3868
+ pii: !capabilityConfig.block_pii_leakage && effectivePiiMasking2,
3869
+ secrets: !capabilityConfig.block_secret_leakage && effectiveSecretMasking2
3870
+ });
2859
3871
  return {
2860
3872
  sanitizedInput: masked.maskedText,
2861
3873
  capabilityConfig,
@@ -2887,13 +3899,18 @@ var AgentID = class {
2887
3899
  apiKey: effectiveApiKey,
2888
3900
  clientEventId: params.clientEventId,
2889
3901
  sdkConfigFetchMs,
3902
+ telemetryMetadata: params.telemetryMetadata,
2890
3903
  runPromptInjectionCheck: !params.skipInjectionScan
2891
3904
  });
2892
3905
  sanitizedInput = enforced.sanitizedInput;
2893
3906
  sdkLocalScanMs = enforced.sdkLocalScanMs;
2894
3907
  const effectivePiiMasking = this.resolveEffectivePiiMasking(capabilityConfig);
2895
- if (!capabilityConfig.block_pii_leakage && effectivePiiMasking) {
2896
- const masked = this.pii.anonymize(sanitizedInput);
3908
+ const effectiveSecretMasking = this.resolveEffectiveSecretMasking(capabilityConfig);
3909
+ if (!capabilityConfig.block_pii_leakage && effectivePiiMasking || !capabilityConfig.block_secret_leakage && effectiveSecretMasking) {
3910
+ const masked = this.pii.anonymize(sanitizedInput, {
3911
+ pii: !capabilityConfig.block_pii_leakage && effectivePiiMasking,
3912
+ secrets: !capabilityConfig.block_secret_leakage && effectiveSecretMasking
3913
+ });
2897
3914
  return {
2898
3915
  sanitizedInput: masked.maskedText,
2899
3916
  capabilityConfig,
@@ -2929,6 +3946,7 @@ var AgentID = class {
2929
3946
  apiKey: effectiveApiKey,
2930
3947
  clientEventId: params.clientEventId,
2931
3948
  sdkConfigFetchMs: refreshedConfig.sdkConfigFetchMs,
3949
+ telemetryMetadata: params.telemetryMetadata,
2932
3950
  runPromptInjectionCheck: true
2933
3951
  });
2934
3952
  return {
@@ -2992,9 +4010,30 @@ var AgentID = class {
2992
4010
  if (!message || typeof message !== "object") {
2993
4011
  return req;
2994
4012
  }
4013
+ const currentContent = message.content;
4014
+ let nextContent = maskedText;
4015
+ if (Array.isArray(currentContent)) {
4016
+ let textReplaced = false;
4017
+ const preservedParts = [];
4018
+ for (const part of currentContent) {
4019
+ if (!part || typeof part !== "object" || part.type !== "text" || typeof part.text !== "string") {
4020
+ preservedParts.push(part);
4021
+ continue;
4022
+ }
4023
+ if (textReplaced) {
4024
+ continue;
4025
+ }
4026
+ textReplaced = true;
4027
+ preservedParts.push({
4028
+ ...part,
4029
+ text: maskedText
4030
+ });
4031
+ }
4032
+ nextContent = textReplaced ? preservedParts : [{ type: "text", text: maskedText }, ...currentContent];
4033
+ }
2995
4034
  newMessages[lastUserIdx] = {
2996
4035
  ...message,
2997
- content: maskedText
4036
+ content: nextContent
2998
4037
  };
2999
4038
  if (!req || typeof req !== "object") {
3000
4039
  return req;
@@ -3013,6 +4052,7 @@ var AgentID = class {
3013
4052
  event_type: "security_policy_violation",
3014
4053
  severity: "high",
3015
4054
  metadata: {
4055
+ ...params.telemetryMetadata ?? {},
3016
4056
  event_type: "security_policy_violation",
3017
4057
  severity: "high",
3018
4058
  system_id: params.systemId,
@@ -3040,6 +4080,7 @@ var AgentID = class {
3040
4080
  event_type: "security_alert",
3041
4081
  severity: "warning",
3042
4082
  metadata: {
4083
+ ...params.guardParams.metadata ?? {},
3043
4084
  source: "guard",
3044
4085
  status: params.status,
3045
4086
  guard_reason: params.reason,
@@ -3482,21 +4523,29 @@ var AgentID = class {
3482
4523
  wrapCompletion(completion, options) {
3483
4524
  if (typeof completion === "string") {
3484
4525
  const masked = this.pii.anonymize(completion);
4526
+ const placeholderOutputMasked = textContainsMappingPlaceholder(
4527
+ completion,
4528
+ options?.piiMapping
4529
+ );
3485
4530
  return {
3486
4531
  mode: "static",
3487
4532
  rawOutput: completion,
3488
4533
  transformedOutput: masked.maskedText,
3489
- outputMasked: masked.maskedText !== completion
4534
+ outputMasked: masked.maskedText !== completion || placeholderOutputMasked
3490
4535
  };
3491
4536
  }
3492
4537
  if (!isAsyncIterable(completion)) {
3493
4538
  const asText = String(completion ?? "");
3494
4539
  const masked = this.pii.anonymize(asText);
4540
+ const placeholderOutputMasked = textContainsMappingPlaceholder(
4541
+ asText,
4542
+ options?.piiMapping
4543
+ );
3495
4544
  return {
3496
4545
  mode: "static",
3497
4546
  rawOutput: asText,
3498
4547
  transformedOutput: masked.maskedText,
3499
- outputMasked: masked.maskedText !== asText
4548
+ outputMasked: masked.maskedText !== asText || placeholderOutputMasked
3500
4549
  };
3501
4550
  }
3502
4551
  const source = completion;
@@ -3506,8 +4555,10 @@ var AgentID = class {
3506
4555
  const isOpenAIStreamFinishChunk = this.isOpenAIStreamFinishChunk.bind(this);
3507
4556
  const rewriteOpenAIStreamChunkForClient = this.rewriteOpenAIStreamChunkForClient.bind(this);
3508
4557
  const createSyntheticOpenAIStreamChunk = this.createSyntheticOpenAIStreamChunk.bind(this);
4558
+ const setOpenAIStreamChunkText = this.setOpenAIStreamChunkText.bind(this);
3509
4559
  const piiManager = this.pii;
3510
4560
  const streamRewriter = options?.deanonymizeForClient === true && options.piiMapping ? createStreamingPlaceholderRewriter(piiManager, options.piiMapping) : null;
4561
+ const maskForClient = options?.maskForClient === true && streamRewriter === null;
3511
4562
  let lastUsage;
3512
4563
  let resolveDone = null;
3513
4564
  let rejectDone = null;
@@ -3520,12 +4571,17 @@ var AgentID = class {
3520
4571
  try {
3521
4572
  let finishChunkFlushed = false;
3522
4573
  let lastChunkTemplate;
4574
+ let clientRawText = "";
4575
+ let clientMaskFlushed = false;
3523
4576
  for await (const chunk of source) {
3524
4577
  const chunkText = extractStreamChunkText(chunk);
3525
- const isFinishChunk = streamRewriter ? isOpenAIStreamFinishChunk(chunk) : false;
4578
+ const isFinishChunk = streamRewriter || maskForClient ? isOpenAIStreamFinishChunk(chunk) : false;
3526
4579
  if (chunkText) {
3527
4580
  await collector.push(chunkText);
3528
4581
  lastChunkTemplate = chunk;
4582
+ if (maskForClient) {
4583
+ clientRawText += chunkText;
4584
+ }
3529
4585
  }
3530
4586
  const chunkUsage = extractStreamChunkUsage(chunk);
3531
4587
  if (chunkUsage) {
@@ -3545,6 +4601,28 @@ var AgentID = class {
3545
4601
  }
3546
4602
  continue;
3547
4603
  }
4604
+ if (maskForClient) {
4605
+ if (isFinishChunk) {
4606
+ const maskedClientText = piiManager.anonymize(clientRawText).maskedText;
4607
+ clientMaskFlushed = true;
4608
+ if (maskedClientText.length > 0) {
4609
+ yield createSyntheticOpenAIStreamChunk(
4610
+ maskedClientText,
4611
+ lastChunkTemplate ?? chunk
4612
+ );
4613
+ }
4614
+ if (chunkText) {
4615
+ setOpenAIStreamChunkText(chunk, "");
4616
+ }
4617
+ yield chunk;
4618
+ finishChunkFlushed = true;
4619
+ continue;
4620
+ }
4621
+ if (!chunkText) {
4622
+ yield chunk;
4623
+ }
4624
+ continue;
4625
+ }
3548
4626
  yield chunk;
3549
4627
  }
3550
4628
  if (streamRewriter && !finishChunkFlushed) {
@@ -3556,14 +4634,27 @@ var AgentID = class {
3556
4634
  );
3557
4635
  }
3558
4636
  }
4637
+ if (maskForClient && !clientMaskFlushed) {
4638
+ const maskedClientText = piiManager.anonymize(clientRawText).maskedText;
4639
+ if (maskedClientText.length > 0) {
4640
+ yield createSyntheticOpenAIStreamChunk(
4641
+ maskedClientText,
4642
+ lastChunkTemplate
4643
+ );
4644
+ }
4645
+ }
3559
4646
  await collector.close();
3560
4647
  const rawOutput = await collector.result;
3561
4648
  const masked = piiManager.anonymize(rawOutput);
4649
+ const placeholderOutputMasked = textContainsMappingPlaceholder(
4650
+ rawOutput,
4651
+ options?.piiMapping
4652
+ );
3562
4653
  resolveDone?.({
3563
4654
  mode: "static",
3564
4655
  rawOutput,
3565
4656
  transformedOutput: masked.maskedText,
3566
- outputMasked: masked.maskedText !== rawOutput,
4657
+ outputMasked: masked.maskedText !== rawOutput || placeholderOutputMasked,
3567
4658
  usage: lastUsage
3568
4659
  });
3569
4660
  } catch (error) {
@@ -3598,6 +4689,37 @@ var AgentID = class {
3598
4689
  );
3599
4690
  }
3600
4691
  }
4692
+ buildOperationLogParams(params) {
4693
+ return createAgentIdOperationLog(params);
4694
+ }
4695
+ async logOperation(params, options) {
4696
+ return this.log(this.buildOperationLogParams(params), options);
4697
+ }
4698
+ async logPromptPreflightStep(params, options) {
4699
+ const telemetry = buildPromptPreflightTelemetry(params);
4700
+ const summary = firstNonEmptyString(telemetry?.step_summary, telemetry?.stepSummary) ?? summarizePromptPreflightResult({
4701
+ verdict: params.verdict,
4702
+ localFallbackApplied: params.local_fallback_applied,
4703
+ localFallbackReason: params.local_fallback_reason
4704
+ });
4705
+ await this.logOperation(
4706
+ {
4707
+ system_id: params.system_id,
4708
+ user_id: params.user_id,
4709
+ request_identity: params.request_identity,
4710
+ input: params.input,
4711
+ output: summary,
4712
+ model: "not_applicable",
4713
+ latency: params.guard_latency_ms ?? void 0,
4714
+ telemetry,
4715
+ client_capabilities: params.client_capabilities
4716
+ },
4717
+ options
4718
+ );
4719
+ }
4720
+ operation(params, options) {
4721
+ return this.logOperation(params, options);
4722
+ }
3601
4723
  /**
3602
4724
  * Analytics alias for telemetry logging.
3603
4725
  */
@@ -3642,49 +4764,56 @@ var AgentID = class {
3642
4764
  if (typeof originalCreate !== "function") return originalCreate;
3643
4765
  return async (...args) => {
3644
4766
  const normalizedCreateArgs = normalizeOpenAICreateArgs(args);
3645
- const req = normalizedCreateArgs?.[0] ?? {};
4767
+ const rawReq = normalizedCreateArgs?.[0] ?? {};
4768
+ const requestTelemetry = extractRequestTelemetryContext(rawReq);
4769
+ const telemetryMetadata = mergeTelemetryContexts(
4770
+ options.telemetry,
4771
+ requestTelemetry
4772
+ );
4773
+ const providerReq = stripRequestTelemetryContext(rawReq);
3646
4774
  const pipelineStartedAt = Date.now();
3647
- const requestLevelApiKey = options.resolveApiKey?.(req) ?? options.apiKey ?? options.api_key;
4775
+ const requestLevelApiKey = options.resolveApiKey?.(rawReq) ?? options.apiKey ?? options.api_key;
3648
4776
  const effectiveApiKey = this.resolveApiKey(requestLevelApiKey);
3649
4777
  const requestOptions = { apiKey: effectiveApiKey };
3650
- const clientEventId = this.resolveClientEventId(req);
4778
+ const clientEventId = this.resolveClientEventId(rawReq);
3651
4779
  const effectiveStrictMode = await this.resolveEffectiveStrictMode(requestOptions);
3652
- const stream = adapter.isStream(req);
4780
+ const stream = adapter.isStream(providerReq);
3653
4781
  let capabilityConfig = this.getCachedCapabilityConfig(requestOptions);
3654
- const userText = adapter.extractInput(req);
3655
- let maskedText = userText;
3656
- let maskedReq = req;
3657
- let createArgs = normalizedCreateArgs;
4782
+ const userText = adapter.extractInput(providerReq);
4783
+ const requestAttachments = adapter.extractAttachments(providerReq);
4784
+ const hasGuardContent = userText !== null || requestAttachments.length > 0;
4785
+ let maskedText = userText ?? "";
4786
+ let maskedReq = providerReq;
4787
+ let createArgs = providerReq === rawReq ? normalizedCreateArgs : [{ ...providerReq }, ...normalizedCreateArgs.slice(1)];
3658
4788
  let mapping = {};
3659
- let shouldDeanonymize = false;
3660
4789
  let sdkConfigFetchMs = 0;
3661
4790
  let sdkLocalScanMs = 0;
3662
- if (userText) {
4791
+ if (hasGuardContent) {
3663
4792
  const prepared = await this.prepareInputForDispatch({
3664
- input: userText,
4793
+ input: userText ?? "",
3665
4794
  systemId,
3666
4795
  stream,
3667
- clientEventId
4796
+ clientEventId,
4797
+ telemetryMetadata
3668
4798
  }, requestOptions);
3669
4799
  capabilityConfig = prepared.capabilityConfig;
3670
4800
  maskedText = prepared.sanitizedInput;
3671
4801
  mapping = prepared.piiMapping ?? {};
3672
- shouldDeanonymize = prepared.shouldDeanonymize === true;
3673
4802
  sdkConfigFetchMs = prepared.sdkConfigFetchMs ?? 0;
3674
4803
  sdkLocalScanMs = prepared.sdkLocalScanMs ?? 0;
3675
- if (maskedText !== userText) {
4804
+ if (maskedText !== (userText ?? "")) {
3676
4805
  maskedReq = this.withMaskedOpenAIRequest(
3677
- req,
4806
+ providerReq,
3678
4807
  maskedText
3679
4808
  );
3680
- const nextCreateArgs = [...normalizedCreateArgs];
4809
+ const nextCreateArgs = [...createArgs];
3681
4810
  nextCreateArgs[0] = maskedReq;
3682
4811
  createArgs = nextCreateArgs;
3683
4812
  }
3684
4813
  }
3685
- if (!maskedText) {
4814
+ if (!hasGuardContent) {
3686
4815
  throw new Error(
3687
- "AgentID: No user message found. Security guard requires string input."
4816
+ "AgentID: No user message or supported inline attachment found. Security guard requires prompt content."
3688
4817
  );
3689
4818
  }
3690
4819
  const verdict = await this.guard({
@@ -3695,6 +4824,8 @@ var AgentID = class {
3695
4824
  client_event_id: clientEventId,
3696
4825
  expected_languages: expectedLanguages,
3697
4826
  request_identity: options.request_identity,
4827
+ metadata: telemetryMetadata,
4828
+ attachments: requestAttachments,
3698
4829
  client_capabilities: this.buildClientCapabilities(
3699
4830
  "openai",
3700
4831
  false,
@@ -3716,22 +4847,43 @@ var AgentID = class {
3716
4847
  apiKey: effectiveApiKey,
3717
4848
  clientEventId,
3718
4849
  sdkConfigFetchMs,
4850
+ telemetryMetadata,
3719
4851
  runPromptInjectionCheck: true
3720
4852
  });
3721
4853
  maskedText = fallback.sanitizedInput;
3722
4854
  sdkLocalScanMs = fallback.sdkLocalScanMs;
3723
4855
  }
3724
4856
  } else {
4857
+ await this.logPromptPreflightStep(
4858
+ {
4859
+ system_id: systemId,
4860
+ user_id: options.user_id,
4861
+ request_identity: options.request_identity,
4862
+ input: maskedText,
4863
+ telemetry: telemetryMetadata,
4864
+ verdict,
4865
+ guard_event_id: verdict.guard_event_id ?? null,
4866
+ guard_latency_ms: typeof verdict.guard_latency_ms === "number" && Number.isFinite(verdict.guard_latency_ms) ? Math.max(0, Math.trunc(verdict.guard_latency_ms)) : Math.max(0, Date.now() - pipelineStartedAt),
4867
+ preflight_for_client_event_id: typeof verdict.client_event_id === "string" && isUuidLike2(verdict.client_event_id) ? verdict.client_event_id : clientEventId,
4868
+ client_capabilities: this.buildClientCapabilities(
4869
+ "openai",
4870
+ false,
4871
+ capabilityConfig
4872
+ ),
4873
+ runtime_surface: "openai_sdk_guard"
4874
+ },
4875
+ requestOptions
4876
+ );
3725
4877
  throw new SecurityBlockError(verdict.reason ?? "guard_denied");
3726
4878
  }
3727
4879
  }
3728
- const currentRequestInput = adapter.extractInput(maskedReq);
4880
+ const currentRequestInput = adapter.extractInput(maskedReq) ?? "";
3729
4881
  if (maskedText !== currentRequestInput) {
3730
4882
  maskedReq = this.withMaskedOpenAIRequest(
3731
- req,
4883
+ providerReq,
3732
4884
  maskedText
3733
4885
  );
3734
- const nextCreateArgs = [...normalizedCreateArgs];
4886
+ const nextCreateArgs = [...createArgs];
3735
4887
  nextCreateArgs[0] = maskedReq;
3736
4888
  createArgs = nextCreateArgs;
3737
4889
  }
@@ -3742,15 +4894,44 @@ var AgentID = class {
3742
4894
  const isShadowMode = verdict.shadow_mode === true;
3743
4895
  const transformedInput = isShadowMode ? maskedText : typeof verdict.transformed_input === "string" && verdict.transformed_input.length > 0 ? verdict.transformed_input : maskedText;
3744
4896
  if (transformedInput !== maskedText) {
4897
+ const serverDerivedMapping = derivePlaceholderMappingFromTransform(
4898
+ maskedText,
4899
+ transformedInput
4900
+ );
4901
+ if (Object.keys(serverDerivedMapping).length > 0) {
4902
+ mapping = mergePiiMappings(mapping, serverDerivedMapping);
4903
+ }
3745
4904
  maskedText = transformedInput;
3746
4905
  maskedReq = this.withMaskedOpenAIRequest(
3747
- req,
4906
+ providerReq,
3748
4907
  transformedInput
3749
4908
  );
3750
- const nextCreateArgs = [...normalizedCreateArgs];
4909
+ const nextCreateArgs = [...createArgs];
3751
4910
  nextCreateArgs[0] = maskedReq;
3752
4911
  createArgs = nextCreateArgs;
3753
4912
  }
4913
+ await this.logPromptPreflightStep(
4914
+ {
4915
+ system_id: systemId,
4916
+ user_id: options.user_id,
4917
+ request_identity: options.request_identity,
4918
+ input: maskedText,
4919
+ telemetry: telemetryMetadata,
4920
+ verdict,
4921
+ guard_event_id: guardEventId,
4922
+ guard_latency_ms: guardLatencyMs,
4923
+ preflight_for_client_event_id: canonicalClientEventId,
4924
+ client_capabilities: this.buildClientCapabilities(
4925
+ "openai",
4926
+ false,
4927
+ capabilityConfig
4928
+ ),
4929
+ local_fallback_applied: localFallbackApplied,
4930
+ local_fallback_reason: localFallbackReason,
4931
+ runtime_surface: "openai_sdk_guard"
4932
+ },
4933
+ requestOptions
4934
+ );
3754
4935
  if (stream) {
3755
4936
  const modelStartedAt2 = Date.now();
3756
4937
  const streamResponse = await originalCreate.apply(compTarget, createArgs);
@@ -3762,7 +4943,8 @@ var AgentID = class {
3762
4943
  })(),
3763
4944
  {
3764
4945
  piiMapping: mapping,
3765
- deanonymizeForClient: shouldDeanonymize
4946
+ deanonymizeForClient: false,
4947
+ maskForClient: !isShadowMode
3766
4948
  }
3767
4949
  );
3768
4950
  if (maskedText && wrappedCompletion.mode === "stream") {
@@ -3781,29 +4963,32 @@ var AgentID = class {
3781
4963
  usage: result.usage,
3782
4964
  latency: modelLatencyMs2,
3783
4965
  event_type: "complete",
3784
- metadata: {
3785
- transformed_input: maskedText,
3786
- transformed_output: result.transformedOutput,
3787
- output_masked: result.outputMasked,
3788
- shadow_mode: isShadowMode,
3789
- simulated_decision: verdict.simulated_decision ?? null,
3790
- simulated_output_decision: isShadowMode && result.outputMasked ? "masked" : "allowed",
3791
- response_streamed: true,
3792
- sdk_local_fallback_applied: localFallbackApplied,
3793
- sdk_local_fallback_reason: localFallbackReason,
3794
- guard_latency_ms: guardLatencyMs,
3795
- model_latency_ms: modelLatencyMs2,
3796
- total_pipeline_latency_ms: totalPipelineLatencyMs2,
3797
- guard_event_id: guardEventId,
3798
- client_event_id: canonicalClientEventId,
3799
- transparency,
3800
- ...buildSdkTimingMetadata({
4966
+ metadata: mergeTelemetryContexts(
4967
+ telemetryMetadata,
4968
+ {
4969
+ transformed_input: maskedText,
4970
+ transformed_output: result.transformedOutput,
4971
+ output_masked: result.outputMasked,
4972
+ shadow_mode: isShadowMode,
4973
+ simulated_decision: verdict.simulated_decision ?? null,
4974
+ simulated_output_decision: isShadowMode && result.outputMasked ? "masked" : "allowed",
4975
+ response_streamed: true,
4976
+ sdk_local_fallback_applied: localFallbackApplied,
4977
+ sdk_local_fallback_reason: localFallbackReason,
4978
+ guard_latency_ms: guardLatencyMs,
4979
+ model_latency_ms: modelLatencyMs2,
4980
+ total_pipeline_latency_ms: totalPipelineLatencyMs2,
4981
+ guard_event_id: guardEventId,
4982
+ client_event_id: canonicalClientEventId,
4983
+ transparency
4984
+ },
4985
+ buildSdkTimingMetadata({
3801
4986
  sdkConfigFetchMs,
3802
4987
  sdkLocalScanMs,
3803
4988
  sdkGuardMs: guardLatencyMs,
3804
4989
  sdkConfigVersion: capabilityConfig.version
3805
4990
  })
3806
- },
4991
+ ),
3807
4992
  client_capabilities: this.buildClientCapabilities(
3808
4993
  "openai",
3809
4994
  false,
@@ -3834,7 +5019,10 @@ var AgentID = class {
3834
5019
  const totalPipelineLatencyMs = Math.max(0, Date.now() - pipelineStartedAt);
3835
5020
  if (maskedText) {
3836
5021
  const output = adapter.extractOutput(res);
3837
- const wrappedCompletion = this.wrapCompletion(output);
5022
+ const wrappedCompletion = this.wrapCompletion(output, {
5023
+ piiMapping: mapping,
5024
+ deanonymizeForClient: false
5025
+ });
3838
5026
  const model = adapter.getModelName(maskedReq, res);
3839
5027
  const usage = adapter.getTokenUsage(res);
3840
5028
  const outputForLog = isShadowMode ? wrappedCompletion.rawOutput : wrappedCompletion.transformedOutput;
@@ -3849,29 +5037,32 @@ var AgentID = class {
3849
5037
  usage,
3850
5038
  latency: modelLatencyMs,
3851
5039
  event_type: "complete",
3852
- metadata: {
3853
- transformed_input: maskedText,
3854
- transformed_output: wrappedCompletion.transformedOutput,
3855
- output_masked: wrappedCompletion.outputMasked,
3856
- shadow_mode: isShadowMode,
3857
- simulated_decision: verdict.simulated_decision ?? null,
3858
- simulated_output_decision: isShadowMode && wrappedCompletion.outputMasked ? "masked" : "allowed",
3859
- response_streamed: false,
3860
- sdk_local_fallback_applied: localFallbackApplied,
3861
- sdk_local_fallback_reason: localFallbackReason,
3862
- guard_latency_ms: guardLatencyMs,
3863
- model_latency_ms: modelLatencyMs,
3864
- total_pipeline_latency_ms: totalPipelineLatencyMs,
3865
- guard_event_id: guardEventId,
3866
- client_event_id: canonicalClientEventId,
3867
- transparency,
3868
- ...buildSdkTimingMetadata({
5040
+ metadata: mergeTelemetryContexts(
5041
+ telemetryMetadata,
5042
+ {
5043
+ transformed_input: maskedText,
5044
+ transformed_output: wrappedCompletion.transformedOutput,
5045
+ output_masked: wrappedCompletion.outputMasked,
5046
+ shadow_mode: isShadowMode,
5047
+ simulated_decision: verdict.simulated_decision ?? null,
5048
+ simulated_output_decision: isShadowMode && wrappedCompletion.outputMasked ? "masked" : "allowed",
5049
+ response_streamed: false,
5050
+ sdk_local_fallback_applied: localFallbackApplied,
5051
+ sdk_local_fallback_reason: localFallbackReason,
5052
+ guard_latency_ms: guardLatencyMs,
5053
+ model_latency_ms: modelLatencyMs,
5054
+ total_pipeline_latency_ms: totalPipelineLatencyMs,
5055
+ guard_event_id: guardEventId,
5056
+ client_event_id: canonicalClientEventId,
5057
+ transparency
5058
+ },
5059
+ buildSdkTimingMetadata({
3869
5060
  sdkConfigFetchMs,
3870
5061
  sdkLocalScanMs,
3871
5062
  sdkGuardMs: guardLatencyMs,
3872
5063
  sdkConfigVersion: capabilityConfig.version
3873
5064
  })
3874
- },
5065
+ ),
3875
5066
  client_capabilities: this.buildClientCapabilities(
3876
5067
  "openai",
3877
5068
  false,
@@ -3888,17 +5079,21 @@ var AgentID = class {
3888
5079
  );
3889
5080
  }
3890
5081
  }
3891
- if (!capabilityConfig.block_pii_leakage && this.resolveEffectivePiiMasking(capabilityConfig) && shouldDeanonymize) {
3892
- const deanon = this.pii.deanonymize(adapter.extractOutput(res), mapping);
5082
+ if (!isShadowMode && maskedText) {
5083
+ const output = adapter.extractOutput(res);
5084
+ const maskedOutput = this.wrapCompletion(output, {
5085
+ piiMapping: mapping,
5086
+ deanonymizeForClient: false
5087
+ }).transformedOutput;
3893
5088
  try {
3894
5089
  if (Array.isArray(res?.choices)) {
3895
5090
  for (const choice of res.choices) {
3896
5091
  const typedChoice = choice;
3897
5092
  if (typedChoice?.message && typeof typedChoice.message.content === "string") {
3898
- typedChoice.message.content = deanon;
5093
+ typedChoice.message.content = maskedOutput;
3899
5094
  }
3900
5095
  if (typedChoice?.delta && typeof typedChoice.delta.content === "string") {
3901
- typedChoice.delta.content = deanon;
5096
+ typedChoice.delta.content = maskedOutput;
3902
5097
  }
3903
5098
  }
3904
5099
  }
@@ -3923,14 +5118,169 @@ var AgentID = class {
3923
5118
  });
3924
5119
  }
3925
5120
  };
5121
+ function mergeWorkflowTrailRequestOptions(base, override) {
5122
+ const apiKey = firstNonEmptyString(override?.apiKey, base?.apiKey);
5123
+ return apiKey ? { apiKey } : void 0;
5124
+ }
5125
+ function appendWorkflowErrorMetadata(metadata, error) {
5126
+ const nextMetadata = { ...metadata ?? {} };
5127
+ if (error instanceof Error) {
5128
+ if (typeof nextMetadata.error_name !== "string") {
5129
+ nextMetadata.error_name = error.name;
5130
+ }
5131
+ if (typeof nextMetadata.error_message !== "string" && error.message.trim().length > 0) {
5132
+ nextMetadata.error_message = error.message.trim();
5133
+ }
5134
+ return Object.keys(nextMetadata).length > 0 ? nextMetadata : void 0;
5135
+ }
5136
+ if (typeof nextMetadata.error_message !== "string" && typeof error !== "undefined") {
5137
+ const errorMessage = String(error).trim();
5138
+ if (errorMessage.length > 0) {
5139
+ nextMetadata.error_message = errorMessage;
5140
+ }
5141
+ }
5142
+ return Object.keys(nextMetadata).length > 0 ? nextMetadata : void 0;
5143
+ }
5144
+ var AgentIDWorkflowStep = class {
5145
+ constructor(params) {
5146
+ this.trail = params.trail;
5147
+ this.workflowStepId = params.workflowStepId;
5148
+ this.startEventId = params.startEventId;
5149
+ this.telemetry = params.telemetry;
5150
+ this.startedAtMs = params.startedAtMs;
5151
+ }
5152
+ resolveStepTelemetry(telemetry) {
5153
+ return mergeTelemetryContexts(
5154
+ this.telemetry,
5155
+ createAgentIdTelemetryContext({
5156
+ workflow_step_id: this.workflowStepId,
5157
+ parent_event_id: this.startEventId
5158
+ }),
5159
+ telemetry
5160
+ );
5161
+ }
5162
+ async log(params = {}, options) {
5163
+ return this.trail.logStep(
5164
+ {
5165
+ ...params,
5166
+ telemetry: this.resolveStepTelemetry(params.telemetry)
5167
+ },
5168
+ options
5169
+ );
5170
+ }
5171
+ async complete(params = {}, options) {
5172
+ return this.log(
5173
+ {
5174
+ ...params,
5175
+ latency: typeof params.latency === "number" ? params.latency : Math.max(0, Date.now() - this.startedAtMs),
5176
+ event_status: params.event_status ?? "completed"
5177
+ },
5178
+ options
5179
+ );
5180
+ }
5181
+ async fail(error, params = {}, options) {
5182
+ return this.log(
5183
+ {
5184
+ ...params,
5185
+ latency: typeof params.latency === "number" ? params.latency : Math.max(0, Date.now() - this.startedAtMs),
5186
+ metadata: appendWorkflowErrorMetadata(params.metadata, error),
5187
+ event_type: params.event_type ?? "error",
5188
+ event_status: params.event_status ?? "failed",
5189
+ severity: params.severity ?? "error"
5190
+ },
5191
+ options
5192
+ );
5193
+ }
5194
+ };
5195
+ var AgentIDWorkflowTrail = class {
5196
+ constructor(options) {
5197
+ this.agent = options.agent;
5198
+ this.systemId = options.system_id;
5199
+ this.userId = options.user_id;
5200
+ this.requestIdentity = options.request_identity;
5201
+ this.telemetry = createAgentIdTelemetryContext(options.telemetry);
5202
+ this.clientCapabilities = options.client_capabilities;
5203
+ this.requestOptions = options.requestOptions;
5204
+ }
5205
+ async logStep(params = {}, options) {
5206
+ const payload = this.agent.buildOperationLogParams({
5207
+ ...params,
5208
+ system_id: this.systemId,
5209
+ user_id: this.userId,
5210
+ request_identity: this.requestIdentity,
5211
+ telemetry: mergeTelemetryContexts(this.telemetry, params.telemetry),
5212
+ client_capabilities: params.client_capabilities ?? this.clientCapabilities
5213
+ });
5214
+ await this.agent.log(
5215
+ payload,
5216
+ mergeWorkflowTrailRequestOptions(this.requestOptions, options)
5217
+ );
5218
+ return payload;
5219
+ }
5220
+ async startStep(params = {}, options) {
5221
+ const startedAtMs = Date.now();
5222
+ const requestedTelemetry = createAgentIdTelemetryContext(params.telemetry);
5223
+ const workflowStepId = firstNonEmptyString(requestedTelemetry?.workflow_step_id, requestedTelemetry?.workflowStepId) ?? createAgentIdCorrelationId();
5224
+ const startTelemetry = mergeTelemetryContexts(
5225
+ requestedTelemetry,
5226
+ createAgentIdTelemetryContext({
5227
+ workflow_step_id: workflowStepId
5228
+ })
5229
+ );
5230
+ const startPayload = await this.logStep(
5231
+ {
5232
+ ...params,
5233
+ telemetry: startTelemetry,
5234
+ event_type: params.event_type ?? "start",
5235
+ event_status: params.event_status ?? "started"
5236
+ },
5237
+ options
5238
+ );
5239
+ return new AgentIDWorkflowStep({
5240
+ trail: this,
5241
+ workflowStepId,
5242
+ startEventId: startPayload.event_id ?? createEventId2(),
5243
+ telemetry: startTelemetry,
5244
+ startedAtMs
5245
+ });
5246
+ }
5247
+ async runStep(params, run, hooks, options) {
5248
+ const step = await this.startStep(params, options);
5249
+ try {
5250
+ const result = await run();
5251
+ const completeParams = {
5252
+ ...hooks?.complete ?? {},
5253
+ ...hooks?.onComplete?.(result) ?? {}
5254
+ };
5255
+ await step.complete(completeParams, options);
5256
+ return result;
5257
+ } catch (error) {
5258
+ const failParams = {
5259
+ ...hooks?.fail ?? {},
5260
+ ...hooks?.onError?.(error) ?? {}
5261
+ };
5262
+ await step.fail(error, failParams, options);
5263
+ throw error;
5264
+ }
5265
+ }
5266
+ };
5267
+ function createAgentIdWorkflowTrail(options) {
5268
+ return new AgentIDWorkflowTrail(options);
5269
+ }
3926
5270
  // Annotate the CommonJS export names for ESM import in node:
3927
5271
  0 && (module.exports = {
3928
5272
  AgentID,
5273
+ AgentIDWorkflowStep,
5274
+ AgentIDWorkflowTrail,
3929
5275
  DependencyError,
3930
5276
  InjectionScanner,
3931
5277
  OpenAIAdapter,
3932
5278
  PIIManager,
3933
5279
  SecurityBlockError,
5280
+ createAgentIdCorrelationId,
5281
+ createAgentIdOperationLog,
5282
+ createAgentIdTelemetryContext,
5283
+ createAgentIdWorkflowTrail,
3934
5284
  getInjectionScanner,
3935
5285
  scanWithRegex
3936
5286
  });