agentid-sdk 0.1.41 → 0.1.42

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
@@ -33,12 +33,15 @@ __export(index_exports, {
33
33
  createAgentIdTelemetryContext: () => createAgentIdTelemetryContext,
34
34
  createAgentIdWorkflowTrail: () => createAgentIdWorkflowTrail,
35
35
  getInjectionScanner: () => getInjectionScanner,
36
+ protectChatState: () => protectChatState,
36
37
  protectMessageHistory: () => protectMessageHistory,
37
38
  scanWithRegex: () => scanWithRegex
38
39
  });
39
40
  module.exports = __toCommonJS(index_exports);
40
41
 
41
42
  // src/adapters.ts
43
+ var MAX_GUARD_ATTACHMENTS = 4;
44
+ var MAX_PROMPT_CONTEXT_CHARS = 64e3;
42
45
  function getLastUserMessage(req) {
43
46
  const messages = req?.messages;
44
47
  if (!Array.isArray(messages)) return null;
@@ -118,31 +121,79 @@ function normalizeImageAttachment(part) {
118
121
  content_base64: imageUrl
119
122
  };
120
123
  }
121
- var OpenAIAdapter = class {
122
- extractInput(req) {
123
- const lastUser = getLastUserMessage(req);
124
- if (!lastUser) return null;
125
- const content = lastUser.content;
126
- if (typeof content === "string") return content;
127
- if (Array.isArray(content)) {
128
- const parts = [];
129
- for (const part of content) {
130
- if (part && typeof part === "object" && typeof part.text === "string") {
131
- parts.push(part.text);
132
- }
124
+ function truncatePromptContext(value) {
125
+ if (value.length <= MAX_PROMPT_CONTEXT_CHARS) {
126
+ return value;
127
+ }
128
+ const headChars = Math.floor((MAX_PROMPT_CONTEXT_CHARS - 32) / 2);
129
+ const tailChars = MAX_PROMPT_CONTEXT_CHARS - headChars - 32;
130
+ return `${value.slice(0, headChars)}
131
+ [...TRUNCATED CONTEXT...]
132
+ ${value.slice(-tailChars)}`;
133
+ }
134
+ function formatPromptContextRole(role) {
135
+ return typeof role === "string" && role.trim().length > 0 ? role.trim() : "message";
136
+ }
137
+ function extractTextParts(content) {
138
+ if (typeof content === "string" && content.length > 0) {
139
+ return [content];
140
+ }
141
+ if (!Array.isArray(content)) {
142
+ return [];
143
+ }
144
+ const parts = [];
145
+ for (const part of content) {
146
+ if (!part || typeof part !== "object") {
147
+ continue;
148
+ }
149
+ if (typeof part.text === "string") {
150
+ const text = part.text;
151
+ if (text.length > 0) {
152
+ parts.push(text);
133
153
  }
134
- return parts.length ? parts.join("") : null;
135
154
  }
136
- return null;
137
155
  }
138
- extractAttachments(req) {
139
- const lastUser = getLastUserMessage(req);
140
- if (!lastUser) return [];
141
- const content = lastUser?.content;
156
+ return parts;
157
+ }
158
+ function extractAttachmentPlaceholders(content) {
159
+ if (!Array.isArray(content)) {
160
+ return [];
161
+ }
162
+ const placeholders = [];
163
+ for (const part of content) {
164
+ if (!part || typeof part !== "object") {
165
+ continue;
166
+ }
167
+ const typedPart = part;
168
+ if (typedPart.type === "file") {
169
+ placeholders.push(
170
+ `[attachment:${normalizeFilename(typedPart.file?.filename, "attachment.bin")}]`
171
+ );
172
+ continue;
173
+ }
174
+ if (typedPart.type === "image_url") {
175
+ const imageUrl = typedPart.image_url?.url;
176
+ placeholders.push(
177
+ imageUrl?.startsWith("data:") ? "[attachment:image]" : "[attachment:image_url]"
178
+ );
179
+ }
180
+ }
181
+ return placeholders;
182
+ }
183
+ function collectUserAttachments(req) {
184
+ const messages = req?.messages;
185
+ if (!Array.isArray(messages)) {
186
+ return [];
187
+ }
188
+ const attachments = [];
189
+ for (const message of messages) {
190
+ if (!message || typeof message !== "object" || message.role !== "user") {
191
+ continue;
192
+ }
193
+ const content = message.content;
142
194
  if (!Array.isArray(content)) {
143
- return [];
195
+ continue;
144
196
  }
145
- const attachments = [];
146
197
  for (const part of content) {
147
198
  if (!part || typeof part !== "object") {
148
199
  continue;
@@ -161,7 +212,57 @@ var OpenAIAdapter = class {
161
212
  }
162
213
  }
163
214
  }
164
- return attachments;
215
+ }
216
+ return attachments.slice(-MAX_GUARD_ATTACHMENTS);
217
+ }
218
+ function serializeOpenAIPromptContext(req) {
219
+ const messages = req?.messages;
220
+ if (!Array.isArray(messages)) {
221
+ return null;
222
+ }
223
+ const entries = [];
224
+ for (const message of messages) {
225
+ if (!message || typeof message !== "object") {
226
+ continue;
227
+ }
228
+ const role = formatPromptContextRole(message.role);
229
+ const content = message.content;
230
+ const fragments = [
231
+ ...extractTextParts(content),
232
+ ...extractAttachmentPlaceholders(content)
233
+ ].filter((fragment) => fragment.length > 0);
234
+ if (fragments.length === 0) {
235
+ continue;
236
+ }
237
+ entries.push(`[${role}] ${fragments.join("\n")}`);
238
+ }
239
+ if (entries.length === 0) {
240
+ return null;
241
+ }
242
+ return truncatePromptContext(entries.join("\n\n"));
243
+ }
244
+ var OpenAIAdapter = class {
245
+ extractInput(req) {
246
+ const lastUser = getLastUserMessage(req);
247
+ if (!lastUser) return null;
248
+ const content = lastUser.content;
249
+ if (typeof content === "string") return content;
250
+ if (Array.isArray(content)) {
251
+ const parts = [];
252
+ for (const part of content) {
253
+ if (part && typeof part === "object" && typeof part.text === "string") {
254
+ parts.push(part.text);
255
+ }
256
+ }
257
+ return parts.length ? parts.join("") : null;
258
+ }
259
+ return null;
260
+ }
261
+ extractAttachments(req) {
262
+ return collectUserAttachments(req);
263
+ }
264
+ extractPromptContext(req) {
265
+ return serializeOpenAIPromptContext(req);
165
266
  }
166
267
  getModelName(req, res) {
167
268
  const model = res?.model ?? req?.model ?? "unknown";
@@ -182,7 +283,7 @@ var OpenAIAdapter = class {
182
283
 
183
284
  // src/sdk-version.ts
184
285
  var FALLBACK_SDK_VERSION = "js-0.0.0-dev";
185
- var AGENTID_SDK_VERSION_HEADER = "js-0.1.41".trim().length > 0 ? "js-0.1.41" : FALLBACK_SDK_VERSION;
286
+ var AGENTID_SDK_VERSION_HEADER = "js-0.1.42".trim().length > 0 ? "js-0.1.42" : FALLBACK_SDK_VERSION;
186
287
 
187
288
  // src/pii-national-identifiers.ts
188
289
  var MAX_CANDIDATES_PER_RULE = 256;
@@ -1050,49 +1151,49 @@ function detectNationalIdentifiers(text, options = {}) {
1050
1151
  var SDK_SECRET_PATTERN_DEFINITIONS = [
1051
1152
  {
1052
1153
  id: "openai_api_key",
1053
- placeholderType: "OPENAI_API_KEY",
1154
+ placeholderType: "SECRET",
1054
1155
  patternSource: "\\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}\\b",
1055
1156
  flags: "iu",
1056
1157
  prefilterTerms: ["sk-", "proj-", "openai"]
1057
1158
  },
1058
1159
  {
1059
1160
  id: "aws_access_key",
1060
- placeholderType: "AWS_ACCESS_KEY",
1161
+ placeholderType: "SECRET",
1061
1162
  patternSource: "\\b(?:AKIA|ASIA)[A-Z0-9]{16}\\b",
1062
1163
  flags: "iu",
1063
1164
  prefilterTerms: ["akia", "asia", "aws"]
1064
1165
  },
1065
1166
  {
1066
1167
  id: "github_token",
1067
- placeholderType: "GITHUB_TOKEN",
1168
+ placeholderType: "SECRET",
1068
1169
  patternSource: "\\b(?:gh[pousr]_[A-Za-z0-9]{24,255}|github_pat_[A-Za-z0-9_]{20,255})\\b",
1069
1170
  flags: "iu",
1070
1171
  prefilterTerms: ["ghp_", "gho_", "ghu_", "ghs_", "ghr_", "github_pat_"]
1071
1172
  },
1072
1173
  {
1073
1174
  id: "slack_token",
1074
- placeholderType: "SLACK_TOKEN",
1175
+ placeholderType: "SECRET",
1075
1176
  patternSource: "\\bxox(?:a|b|p|r|s)-[A-Za-z0-9-]{10,200}\\b",
1076
1177
  flags: "iu",
1077
1178
  prefilterTerms: ["xoxa-", "xoxb-", "xoxp-", "xoxr-", "xoxs-", "slack"]
1078
1179
  },
1079
1180
  {
1080
1181
  id: "slack_webhook_url",
1081
- placeholderType: "SLACK_WEBHOOK_URL",
1182
+ placeholderType: "SECRET",
1082
1183
  patternSource: "https:\\/\\/hooks\\.slack\\.com\\/services\\/[A-Za-z0-9/_-]{20,}",
1083
1184
  flags: "iu",
1084
1185
  prefilterTerms: ["hooks.slack.com/services", "slack"]
1085
1186
  },
1086
1187
  {
1087
1188
  id: "discord_webhook_url",
1088
- placeholderType: "DISCORD_WEBHOOK_URL",
1189
+ placeholderType: "SECRET",
1089
1190
  patternSource: "https:\\/\\/discord(?:app)?\\.com\\/api\\/webhooks\\/\\d+\\/[A-Za-z0-9_-]{16,}",
1090
1191
  flags: "iu",
1091
1192
  prefilterTerms: ["discord.com/api/webhooks", "discordapp.com/api/webhooks", "discord"]
1092
1193
  },
1093
1194
  {
1094
1195
  id: "stripe_secret_key",
1095
- placeholderType: "STRIPE_SECRET_KEY",
1196
+ placeholderType: "SECRET",
1096
1197
  patternSource: "\\b(?:sk|pk|ak|rk)_(?:live|test)_[A-Za-z0-9]+\\b",
1097
1198
  flags: "iu",
1098
1199
  prefilterTerms: [
@@ -1109,49 +1210,49 @@ var SDK_SECRET_PATTERN_DEFINITIONS = [
1109
1210
  },
1110
1211
  {
1111
1212
  id: "google_api_key",
1112
- placeholderType: "GOOGLE_API_KEY",
1213
+ placeholderType: "SECRET",
1113
1214
  patternSource: "\\bAIza[0-9A-Za-z_-]{35}\\b",
1114
1215
  flags: "iu",
1115
1216
  prefilterTerms: ["aiza", "google"]
1116
1217
  },
1117
1218
  {
1118
1219
  id: "anthropic_api_key",
1119
- placeholderType: "ANTHROPIC_API_KEY",
1220
+ placeholderType: "SECRET",
1120
1221
  patternSource: "\\bsk-ant-(?:api\\d{2}-)?[A-Za-z0-9_-]{20,}\\b",
1121
1222
  flags: "iu",
1122
1223
  prefilterTerms: ["sk-ant-", "anthropic"]
1123
1224
  },
1124
1225
  {
1125
1226
  id: "evm_private_key",
1126
- placeholderType: "EVM_PRIVATE_KEY",
1227
+ placeholderType: "SECRET",
1127
1228
  patternSource: "\\b0x[a-fA-F0-9]{64}\\b",
1128
1229
  flags: "iu",
1129
1230
  prefilterTerms: ["0x", "ethereum", "evm", "private key"]
1130
1231
  },
1131
1232
  {
1132
1233
  id: "jwt_token",
1133
- placeholderType: "JWT_TOKEN",
1234
+ placeholderType: "SECRET",
1134
1235
  patternSource: "\\beyJ[A-Za-z0-9_-]{6,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\b",
1135
1236
  flags: "iu",
1136
1237
  prefilterTerms: ["eyj", "jwt", "bearer"]
1137
1238
  },
1138
1239
  {
1139
1240
  id: "bearer_token",
1140
- placeholderType: "BEARER_TOKEN",
1241
+ placeholderType: "SECRET",
1141
1242
  patternSource: "\\bauthorization\\b\\s*[:=]\\s*bearer\\s+[A-Za-z0-9._~+\\/-]{16,}|\\bbearer\\s+[A-Za-z0-9._~+\\/-]{24,}",
1142
1243
  flags: "iu",
1143
1244
  prefilterTerms: ["authorization", "bearer"]
1144
1245
  },
1145
1246
  {
1146
1247
  id: "api_key_header",
1147
- placeholderType: "API_KEY_HEADER",
1248
+ placeholderType: "SECRET",
1148
1249
  patternSource: "\\bx[-_]?api[-_]?key\\b\\s*[:=]\\s*[A-Za-z0-9._~+\\/-]{16,}",
1149
1250
  flags: "iu",
1150
1251
  prefilterTerms: ["x-api-key", "api-key", "x_api_key", "api_key"]
1151
1252
  },
1152
1253
  {
1153
1254
  id: "credential_assignment",
1154
- placeholderType: "CREDENTIAL_ASSIGNMENT",
1255
+ placeholderType: "SECRET",
1155
1256
  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,})`,
1156
1257
  flags: "iu",
1157
1258
  prefilterTerms: [
@@ -1167,28 +1268,28 @@ var SDK_SECRET_PATTERN_DEFINITIONS = [
1167
1268
  },
1168
1269
  {
1169
1270
  id: "password_assignment",
1170
- placeholderType: "PASSWORD_ASSIGNMENT",
1271
+ placeholderType: "PASSWORD",
1171
1272
  patternSource: `(?:\\b|["'])(?:password|passwd|pwd|heslo)(?:\\b|["'])\\s*(?:(?::|=|=>)|(?:is|are|was|were|je)\\b)?\\s*(?:"[A-Za-z0-9._~!@#$%^&*+=\\/-]{8,}"|'[A-Za-z0-9._~!@#$%^&*+=\\/-]{8,}'|[A-Za-z0-9._~!@#$%^&*+=\\/-]{8,})`,
1172
1273
  flags: "iu",
1173
1274
  prefilterTerms: ["password", "passwd", "pwd", "heslo"]
1174
1275
  },
1175
1276
  {
1176
1277
  id: "private_key_material",
1177
- placeholderType: "PRIVATE_KEY_MATERIAL",
1278
+ placeholderType: "SECRET",
1178
1279
  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)-----|$)",
1179
1280
  flags: "iu",
1180
1281
  prefilterTerms: ["begin private key", "begin pgp private key block", "private key"]
1181
1282
  },
1182
1283
  {
1183
1284
  id: "azure_connection_string",
1184
- placeholderType: "AZURE_CONNECTION_STRING",
1285
+ placeholderType: "SECRET",
1185
1286
  patternSource: "\\bDefaultEndpointsProtocol=https;AccountName=[A-Za-z0-9.-]{3,};AccountKey=[A-Za-z0-9+/=]{20,}(?:;EndpointSuffix=[A-Za-z0-9.-]+)?\\b",
1186
1287
  flags: "iu",
1187
1288
  prefilterTerms: ["defaultendpointsprotocol", "accountname", "accountkey", "azure"]
1188
1289
  },
1189
1290
  {
1190
1291
  id: "azure_sas_token",
1191
- placeholderType: "AZURE_SAS_TOKEN",
1292
+ placeholderType: "SECRET",
1192
1293
  patternSource: "\\bsv=[^\\s&]{2,}&[^\\s]{0,200}\\bsig=[A-Za-z0-9%/+_-]{16,}",
1193
1294
  flags: "iu",
1194
1295
  prefilterTerms: ["sv=", "sig=", "accountkey", "azure"]
@@ -1251,19 +1352,70 @@ function rangesOverlap(left, right) {
1251
1352
  return left.start < right.end && right.start < left.end;
1252
1353
  }
1253
1354
  function detectionPriority(type) {
1254
- 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(
1255
- type
1256
- )) {
1355
+ const normalizedType = toPlaceholderType(type);
1356
+ if (normalizedType === "SECRET") {
1257
1357
  return 100;
1258
1358
  }
1259
- if (/^(?:CREDENTIAL_ASSIGNMENT|PASSWORD_ASSIGNMENT|PRIVATE_KEY_MATERIAL|ENV_SECRET_ASSIGNMENT)$/u.test(type)) {
1359
+ if (normalizedType === "PASSWORD") {
1360
+ return 90;
1361
+ }
1362
+ if (/^(?:CREDENTIAL_ASSIGNMENT|PRIVATE_KEY_MATERIAL|ENV_SECRET_ASSIGNMENT)$/u.test(
1363
+ normalizedType
1364
+ )) {
1260
1365
  return 80;
1261
1366
  }
1262
- if (type === "PERSON_NAME" || type === "PERSON") {
1367
+ if (normalizedType === "PERSON_NAME" || normalizedType === "PERSON") {
1263
1368
  return 10;
1264
1369
  }
1265
1370
  return 50;
1266
1371
  }
1372
+ function isPasswordPlaceholderType(type) {
1373
+ return /^(?:PASSWORD_ASSIGNMENT|BASIC_AUTH_PASSWORD)$/u.test(type);
1374
+ }
1375
+ function isGenericSecretPlaceholderType(type) {
1376
+ return /^(?: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|CREDENTIAL_ASSIGNMENT|PRIVATE_KEY_MATERIAL|ENV_SECRET_ASSIGNMENT|AZURE_CONNECTION_STRING|AZURE_SAS_TOKEN|DISCORD_WEBHOOK_TOKEN)$/u.test(
1377
+ type
1378
+ );
1379
+ }
1380
+ function toPlaceholderType(type) {
1381
+ const normalized = String(type ?? "").trim().toUpperCase();
1382
+ if (isPasswordPlaceholderType(normalized)) {
1383
+ return "PASSWORD";
1384
+ }
1385
+ if (isGenericSecretPlaceholderType(normalized)) {
1386
+ return "SECRET";
1387
+ }
1388
+ return normalized || "PII";
1389
+ }
1390
+ function trimLeadingAddressContext(value) {
1391
+ const trimmed = value.replace(
1392
+ /^(?:(?:na\s+)?adrese|(?:se\s+)?(?:s[ií]dlem|bydli[sš]t[ěe]m|bytem|adresa(?:\s+bydli[sš]t[ěe])?))\s*[:,-]?\s*/iu,
1393
+ ""
1394
+ );
1395
+ if (!trimmed || trimmed === value) {
1396
+ return { text: value, offset: 0 };
1397
+ }
1398
+ return {
1399
+ text: trimmed,
1400
+ offset: value.indexOf(trimmed)
1401
+ };
1402
+ }
1403
+ function normalizeDetection(detection) {
1404
+ if (detection.type !== "ADDRESS") {
1405
+ return detection;
1406
+ }
1407
+ const trimmed = trimLeadingAddressContext(detection.text);
1408
+ if (trimmed.offset <= 0 || trimmed.text === detection.text) {
1409
+ return detection;
1410
+ }
1411
+ const start = detection.start + trimmed.offset;
1412
+ return {
1413
+ ...detection,
1414
+ start,
1415
+ end: start + trimmed.text.length,
1416
+ text: trimmed.text
1417
+ };
1418
+ }
1267
1419
  var PHONE_CONTEXT_KEYWORDS = [
1268
1420
  "tel",
1269
1421
  "phone",
@@ -1378,6 +1530,19 @@ var PERSON_NAME_STOPWORDS = /* @__PURE__ */ new Set([
1378
1530
  "security",
1379
1531
  "instructions",
1380
1532
  "instruction",
1533
+ "authorized",
1534
+ "audit",
1535
+ "article",
1536
+ "compliance",
1537
+ "global",
1538
+ "governance",
1539
+ "charter",
1540
+ "initialization",
1541
+ "sequence",
1542
+ "prefix",
1543
+ "prefixes",
1544
+ "priority",
1545
+ "violation",
1381
1546
  "google",
1382
1547
  "form",
1383
1548
  "forms",
@@ -1452,6 +1617,21 @@ var TECHNICAL_CONTEXT_SYMBOL_REGEX = /:\/\/|`|\{|\}|\[|\]|\(|\)|;|\$|=>|::|\/\//
1452
1617
  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;
1453
1618
  var NAME_VALUE_ASSIGNMENT_BEFORE_CANDIDATE_REGEX = /(?:[:=]|=>|-|\b(?:is|was|je|jsou|jmenuje|called|named|ist|sind|lautet|est|es)\b)\s*$/iu;
1454
1619
  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;
1620
+ var ADDRESS_HOUSE_NUMBER_PATTERN = String.raw`\d{1,5}(?:\/\d{1,5}[A-Za-z]?)?[A-Za-z]?`;
1621
+ var ADDRESS_POSTAL_CODE_PATTERN = String.raw`(?:\d{3}\s?\d{2}|\d{5})`;
1622
+ var ADDRESS_STREET_LABEL_PATTERN = String.raw`(?:ulici|ulice|ul\.?|street|st\.?|road|rd\.?|avenue|ave\.?|n[aá]m[eě]st[ií]|t[řr][íi]da|alej|n[aá]b[řr]ež[ií])`;
1623
+ var ADDRESS_WITH_ANCHOR_RE = new RegExp(
1624
+ String.raw`\b(?:bydl[ií]m\s+na|bydlim\s+na|bytem|bydli[sš]t[eě]|adresa|na\s+ulici|v\s+ulici|doru[cč]ovac[ií]\s+adresa|koresponden[cč]n[ií]\s+adresa|faktura[cč]n[ií]\s+adresa|se\s+s[ií]dlem|z[ií]ju\s+v|ziju\s+v|zjiu\s+v)\b[\s,:-]{0,12}((?:(?:${ADDRESS_STREET_LABEL_PATTERN})\s+)?(?:\p{L}[\p{L}'’-]{2,}\s+){0,4}${ADDRESS_HOUSE_NUMBER_PATTERN}(?:(?:,\s*|\s+)(?:${ADDRESS_POSTAL_CODE_PATTERN}))?(?:(?:,\s*|\s+)(?:v|ve)\s+)?(?:(?:,\s*|\s+)(?:\p{L}[\p{L}'’-]{2,})(?:\s+\p{L}[\p{L}'’-]{2,}){0,2})?)`,
1625
+ "giu"
1626
+ );
1627
+ var ADDRESS_CITY_NUMBER_WITH_ANCHOR_RE = new RegExp(
1628
+ String.raw`\b(?:z[ií]ju\s+v|ziju\s+v|zjiu\s+v|v\s+obci|v\s+katastru\s+obce)\b[\s,:-]{0,12}((?:\p{L}[\p{L}'’-]{2,})(?:\s+\p{L}[\p{L}'’-]{2,}){0,2}\s+${ADDRESS_HOUSE_NUMBER_PATTERN})`,
1629
+ "giu"
1630
+ );
1631
+ var ADDRESS_STANDALONE_RE = new RegExp(
1632
+ String.raw`\b((?:(?:${ADDRESS_STREET_LABEL_PATTERN})\s+)?(?:\p{L}[\p{L}'’-]{2,}\s+){0,4}${ADDRESS_HOUSE_NUMBER_PATTERN}(?:,\s*|\s+)(?:${ADDRESS_POSTAL_CODE_PATTERN})(?:,\s*|\s+)(?:\p{L}[\p{L}'’-]{2,}(?:\s+\p{L}[\p{L}'’-]{2,}){0,2}))`,
1633
+ "gu"
1634
+ );
1455
1635
  function hasPhoneContext(text, matchStartIndex, windowSize = 50) {
1456
1636
  const start = Math.max(0, matchStartIndex - windowSize);
1457
1637
  const windowLower = text.slice(start, matchStartIndex).toLowerCase();
@@ -1503,6 +1683,26 @@ function isLikelyPersonNameCandidate(candidate, contextWindow) {
1503
1683
  }
1504
1684
  return true;
1505
1685
  }
1686
+ function isLikelyAddressCandidate(candidate) {
1687
+ if (!/\d/u.test(candidate)) {
1688
+ return false;
1689
+ }
1690
+ const normalized = normalizePersonWord(candidate);
1691
+ const words = candidate.trim().split(/\s+/).filter(Boolean);
1692
+ if (words.length < 2) {
1693
+ return false;
1694
+ }
1695
+ const numberIndex = words.findIndex((word) => /\d/u.test(word));
1696
+ if (numberIndex <= 0) {
1697
+ return false;
1698
+ }
1699
+ const letterWordRe = /^\p{L}[\p{L}'’-]*$/u;
1700
+ const beforeCount = words.slice(0, numberIndex).filter((word) => letterWordRe.test(word)).length;
1701
+ const afterCount = words.slice(numberIndex + 1).filter((word) => letterWordRe.test(word)).length;
1702
+ return /\b(?:ulici|ulice|ul\.|street|road|avenue|namesti|trida|alej|nabrezi)\b/iu.test(
1703
+ normalized
1704
+ ) || /\b\d{3}\s?\d{2}\b|\b\d{5}\b/u.test(candidate) || beforeCount >= 1 && afterCount >= 1;
1705
+ }
1506
1706
  var PIIManager = class {
1507
1707
  /**
1508
1708
  * Reversible local-first masking using <TYPE_INDEX> placeholders.
@@ -1583,13 +1783,55 @@ var PIIManager = class {
1583
1783
  });
1584
1784
  for (const match of nationalIdMatches) {
1585
1785
  if (match.start < 0 || match.end <= match.start) continue;
1786
+ const detectionType = match.type === "address_postal" ? "ADDRESS" : match.type === "birth_number" ? "BIRTH_NUMBER" : "NATIONAL_ID";
1586
1787
  detections.push({
1587
1788
  start: match.start,
1588
1789
  end: match.end,
1589
- type: "NATIONAL_ID",
1790
+ type: detectionType,
1590
1791
  text: text.slice(match.start, match.end)
1591
1792
  });
1592
1793
  }
1794
+ ADDRESS_WITH_ANCHOR_RE.lastIndex = 0;
1795
+ for (const match of text.matchAll(ADDRESS_WITH_ANCHOR_RE)) {
1796
+ if (match.index == null) continue;
1797
+ const value = match[1] ?? "";
1798
+ if (!value || !isLikelyAddressCandidate(value)) continue;
1799
+ const localIndex = match[0].lastIndexOf(value);
1800
+ const start = match.index + Math.max(0, localIndex);
1801
+ detections.push({
1802
+ start,
1803
+ end: start + value.length,
1804
+ type: "ADDRESS",
1805
+ text: value
1806
+ });
1807
+ }
1808
+ ADDRESS_CITY_NUMBER_WITH_ANCHOR_RE.lastIndex = 0;
1809
+ for (const match of text.matchAll(ADDRESS_CITY_NUMBER_WITH_ANCHOR_RE)) {
1810
+ if (match.index == null) continue;
1811
+ const value = match[1] ?? "";
1812
+ if (!value || !isLikelyAddressCandidate(value)) continue;
1813
+ const localIndex = match[0].lastIndexOf(value);
1814
+ const start = match.index + Math.max(0, localIndex);
1815
+ detections.push({
1816
+ start,
1817
+ end: start + value.length,
1818
+ type: "ADDRESS",
1819
+ text: value
1820
+ });
1821
+ }
1822
+ ADDRESS_STANDALONE_RE.lastIndex = 0;
1823
+ for (const match of text.matchAll(ADDRESS_STANDALONE_RE)) {
1824
+ if (match.index == null) continue;
1825
+ const value = match[1] ?? match[0];
1826
+ if (!value || !isLikelyAddressCandidate(value)) continue;
1827
+ const start = match.index;
1828
+ detections.push({
1829
+ start,
1830
+ end: start + value.length,
1831
+ type: "ADDRESS",
1832
+ text: value
1833
+ });
1834
+ }
1593
1835
  }
1594
1836
  if (resolvedOptions.secrets) {
1595
1837
  BASIC_AUTH_PASSWORD_RE.lastIndex = 0;
@@ -1639,13 +1881,17 @@ var PIIManager = class {
1639
1881
  }
1640
1882
  }
1641
1883
  }
1642
- const kept = normalizeDetections(text, detections);
1884
+ const kept = normalizeDetections(
1885
+ text,
1886
+ detections.map((detection) => normalizeDetection(detection))
1887
+ );
1643
1888
  if (!kept.length) return { maskedText: text, mapping: {} };
1644
1889
  const counters = {};
1645
1890
  const mapping = {};
1646
1891
  const replacements = kept.map((d) => {
1647
- counters[d.type] = (counters[d.type] ?? 0) + 1;
1648
- const placeholder = `<${d.type}_${counters[d.type]}>`;
1892
+ const placeholderType = toPlaceholderType(d.type);
1893
+ counters[placeholderType] = (counters[placeholderType] ?? 0) + 1;
1894
+ const placeholder = `<${placeholderType}_${counters[placeholderType]}>`;
1649
1895
  mapping[placeholder] = d.text;
1650
1896
  return { ...d, placeholder };
1651
1897
  });
@@ -2156,7 +2402,6 @@ var MAX_ANALYSIS_WINDOW = 8192;
2156
2402
  var WINDOW_SLICE_SIZE = 4e3;
2157
2403
  var WORD_BOUNDARY_SCAN = 120;
2158
2404
  var AI_TIMEOUT_MS = 2e3;
2159
- var TELEMETRY_SNIPPET_LIMIT = 4e3;
2160
2405
  var AI_OPENAI_MODEL = "gpt-4o-mini";
2161
2406
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
2162
2407
  var EN_STOPWORDS = /* @__PURE__ */ new Set([
@@ -2341,143 +2586,6 @@ function getOpenAiApiKey() {
2341
2586
  }
2342
2587
  return key.trim();
2343
2588
  }
2344
- async function sha256Hex(text) {
2345
- const data = new TextEncoder().encode(text ?? "");
2346
- const subtle = globalThis.crypto?.subtle;
2347
- if (subtle?.digest) {
2348
- const buf = await subtle.digest("SHA-256", data);
2349
- return Array.from(new Uint8Array(buf)).map((b) => b.toString(16).padStart(2, "0")).join("");
2350
- }
2351
- return sha256HexFallback(data);
2352
- }
2353
- function sha256HexFallback(data) {
2354
- const K = [
2355
- 1116352408,
2356
- 1899447441,
2357
- 3049323471,
2358
- 3921009573,
2359
- 961987163,
2360
- 1508970993,
2361
- 2453635748,
2362
- 2870763221,
2363
- 3624381080,
2364
- 310598401,
2365
- 607225278,
2366
- 1426881987,
2367
- 1925078388,
2368
- 2162078206,
2369
- 2614888103,
2370
- 3248222580,
2371
- 3835390401,
2372
- 4022224774,
2373
- 264347078,
2374
- 604807628,
2375
- 770255983,
2376
- 1249150122,
2377
- 1555081692,
2378
- 1996064986,
2379
- 2554220882,
2380
- 2821834349,
2381
- 2952996808,
2382
- 3210313671,
2383
- 3336571891,
2384
- 3584528711,
2385
- 113926993,
2386
- 338241895,
2387
- 666307205,
2388
- 773529912,
2389
- 1294757372,
2390
- 1396182291,
2391
- 1695183700,
2392
- 1986661051,
2393
- 2177026350,
2394
- 2456956037,
2395
- 2730485921,
2396
- 2820302411,
2397
- 3259730800,
2398
- 3345764771,
2399
- 3516065817,
2400
- 3600352804,
2401
- 4094571909,
2402
- 275423344,
2403
- 430227734,
2404
- 506948616,
2405
- 659060556,
2406
- 883997877,
2407
- 958139571,
2408
- 1322822218,
2409
- 1537002063,
2410
- 1747873779,
2411
- 1955562222,
2412
- 2024104815,
2413
- 2227730452,
2414
- 2361852424,
2415
- 2428436474,
2416
- 2756734187,
2417
- 3204031479,
2418
- 3329325298
2419
- ];
2420
- const H = [
2421
- 1779033703,
2422
- 3144134277,
2423
- 1013904242,
2424
- 2773480762,
2425
- 1359893119,
2426
- 2600822924,
2427
- 528734635,
2428
- 1541459225
2429
- ];
2430
- const length = data.length;
2431
- const bitLengthHi = Math.floor(length * 8 / 4294967296);
2432
- const bitLengthLo = length * 8 >>> 0;
2433
- const paddedLength = length + 9 + 63 >> 6 << 6 >>> 0;
2434
- const padded = new Uint8Array(paddedLength);
2435
- padded.set(data);
2436
- padded[length] = 128;
2437
- const view = new DataView(padded.buffer);
2438
- view.setUint32(paddedLength - 8, bitLengthHi, false);
2439
- view.setUint32(paddedLength - 4, bitLengthLo, false);
2440
- const w = new Uint32Array(64);
2441
- for (let offset = 0; offset < paddedLength; offset += 64) {
2442
- for (let i = 0; i < 16; i += 1) {
2443
- w[i] = view.getUint32(offset + i * 4, false);
2444
- }
2445
- for (let i = 16; i < 64; i += 1) {
2446
- const s0 = rightRotate(w[i - 15], 7) ^ rightRotate(w[i - 15], 18) ^ w[i - 15] >>> 3;
2447
- const s1 = rightRotate(w[i - 2], 17) ^ rightRotate(w[i - 2], 19) ^ w[i - 2] >>> 10;
2448
- w[i] = (w[i - 16] + s0 >>> 0) + (w[i - 7] + s1 >>> 0) >>> 0;
2449
- }
2450
- let [a, b, c, d, e, f, g, h] = H;
2451
- for (let i = 0; i < 64; i += 1) {
2452
- const S1 = rightRotate(e, 6) ^ rightRotate(e, 11) ^ rightRotate(e, 25);
2453
- const ch = e & f ^ ~e & g;
2454
- const temp1 = ((h + S1 >>> 0) + (ch + K[i] >>> 0) >>> 0) + w[i] >>> 0;
2455
- const S0 = rightRotate(a, 2) ^ rightRotate(a, 13) ^ rightRotate(a, 22);
2456
- const maj = a & b ^ a & c ^ b & c;
2457
- const temp2 = S0 + maj >>> 0;
2458
- h = g;
2459
- g = f;
2460
- f = e;
2461
- e = d + temp1 >>> 0;
2462
- d = c;
2463
- c = b;
2464
- b = a;
2465
- a = temp1 + temp2 >>> 0;
2466
- }
2467
- H[0] = H[0] + a >>> 0;
2468
- H[1] = H[1] + b >>> 0;
2469
- H[2] = H[2] + c >>> 0;
2470
- H[3] = H[3] + d >>> 0;
2471
- H[4] = H[4] + e >>> 0;
2472
- H[5] = H[5] + f >>> 0;
2473
- H[6] = H[6] + g >>> 0;
2474
- H[7] = H[7] + h >>> 0;
2475
- }
2476
- return H.map((value) => value.toString(16).padStart(8, "0")).join("");
2477
- }
2478
- function rightRotate(value, shift) {
2479
- return value >>> shift | value << 32 - shift;
2480
- }
2481
2589
  function safeJsonParse(raw) {
2482
2590
  try {
2483
2591
  return JSON.parse(raw);
@@ -2553,22 +2661,11 @@ async function runAICheck(anonymizedWindow) {
2553
2661
  clearTimeout(timeout);
2554
2662
  }
2555
2663
  }
2556
- function truncateSnippet(value) {
2557
- if (!value) {
2558
- return "";
2559
- }
2560
- if (value.length <= TELEMETRY_SNIPPET_LIMIT) {
2561
- return value;
2562
- }
2563
- return value.slice(0, TELEMETRY_SNIPPET_LIMIT);
2564
- }
2565
2664
  async function reportSecurityEvent(options) {
2566
2665
  if (typeof fetch !== "function") {
2567
2666
  return;
2568
2667
  }
2569
- const snippet = truncateSnippet(options.snippet);
2570
- const snippetHash = snippet ? await sha256Hex(snippet) : "";
2571
- const inputValue = options.storePii ? snippet : snippetHash;
2668
+ const inputValue = "[REDACTED]";
2572
2669
  const eventId = createEventId(options.eventId ?? options.clientEventId);
2573
2670
  const metadata = {
2574
2671
  ...options.telemetryMetadata ?? {},
@@ -2578,13 +2675,9 @@ async function reportSecurityEvent(options) {
2578
2675
  language: options.language,
2579
2676
  ai_scan_status: options.aiStatus ?? null,
2580
2677
  reason: options.reason ?? null,
2581
- client_event_id: eventId
2678
+ client_event_id: eventId,
2679
+ transformed_input: "[REDACTED]"
2582
2680
  };
2583
- if (options.storePii) {
2584
- metadata.snippet = snippet;
2585
- } else {
2586
- metadata.snippet_hash = snippetHash;
2587
- }
2588
2681
  const payload = {
2589
2682
  event_id: eventId,
2590
2683
  system_id: options.systemId,
@@ -2864,8 +2957,8 @@ function isInfrastructureGuardReason(reason) {
2864
2957
  if (!reason) return false;
2865
2958
  return reason === "system_failure" || reason === "system_failure_db_unavailable" || reason === "logging_failed" || reason === "server_error" || reason === "guard_unreachable" || reason === "api_key_pepper_missing" || reason === "encryption_key_missing";
2866
2959
  }
2867
- function isGuardFailureEligibleForLocalFallback(reason) {
2868
- return reason === "network_error_strict_mode" || reason === "server_error" || isInfrastructureGuardReason(reason);
2960
+ function isFailOpenGuardBypassReason(reason) {
2961
+ return reason === "timeout_fallback" || reason === "guard_unreachable" || reason === "system_failure_fail_open";
2869
2962
  }
2870
2963
  function isFailCloseIngestReason(reason) {
2871
2964
  if (!reason) return false;
@@ -2900,6 +2993,14 @@ function sanitizeIngestText(value) {
2900
2993
  const text = typeof value === "string" ? value : String(value ?? "");
2901
2994
  return text.slice(0, MAX_INGEST_TEXT_CHARS);
2902
2995
  }
2996
+ function getZeroRetentionInput(rawInput, candidateInput) {
2997
+ const raw = typeof rawInput === "string" ? rawInput : "";
2998
+ const candidate = typeof candidateInput === "string" ? candidateInput : "";
2999
+ if (candidate.length > 0 && candidate !== raw) {
3000
+ return candidate;
3001
+ }
3002
+ return "[REDACTED]";
3003
+ }
2903
3004
  function normalizeExpectedLanguages(value) {
2904
3005
  if (!Array.isArray(value)) {
2905
3006
  return void 0;
@@ -3575,6 +3676,29 @@ function textContainsMappingPlaceholder(text, mapping) {
3575
3676
  }
3576
3677
  return Object.keys(mapping).some((placeholder) => placeholder.length > 0 && text.includes(placeholder));
3577
3678
  }
3679
+ function isSecretPlaceholder(placeholder) {
3680
+ const normalized = placeholder.replace(/[<>]/g, "").replace(/_\d+$/u, "").toUpperCase();
3681
+ return normalized.includes("PASSWORD") || normalized.includes("SECRET") || normalized.includes("TOKEN") || normalized.includes("API_KEY") || normalized.includes("CREDENTIAL") || normalized.includes("PRIVATE_KEY");
3682
+ }
3683
+ function getMaskingTelemetryFromMapping(mapping) {
3684
+ const placeholders = Object.keys(mapping ?? {}).filter((placeholder) => placeholder.length > 0);
3685
+ return {
3686
+ piiApplied: placeholders.some((placeholder) => !isSecretPlaceholder(placeholder)),
3687
+ secretApplied: placeholders.some(isSecretPlaceholder)
3688
+ };
3689
+ }
3690
+ function normalizePiiMapping(value) {
3691
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
3692
+ return void 0;
3693
+ }
3694
+ const entries = Object.entries(value).filter(
3695
+ ([placeholder, replacement]) => placeholder.length > 0 && typeof replacement === "string"
3696
+ );
3697
+ if (entries.length === 0) {
3698
+ return void 0;
3699
+ }
3700
+ return Object.fromEntries(entries);
3701
+ }
3578
3702
  var SecurityBlockError = class extends Error {
3579
3703
  constructor(reason = "guard_denied") {
3580
3704
  super(`AgentID: Security Blocked (${reason})`);
@@ -3652,16 +3776,18 @@ var AgentID = class {
3652
3776
  getEffectiveSecretMaskingForConfig(capabilityConfig) {
3653
3777
  return this.resolveEffectiveSecretMasking(capabilityConfig);
3654
3778
  }
3655
- buildClientCapabilities(framework = "js_sdk", hasFeedbackHandler = false, capabilityConfig) {
3779
+ buildClientCapabilities(framework = "js_sdk", hasFeedbackHandler = false, capabilityConfig, appliedMasking) {
3780
+ const piiMaskingEnabled = typeof appliedMasking?.piiApplied === "boolean" ? appliedMasking.piiApplied : this.resolveEffectivePiiMasking(
3781
+ capabilityConfig ?? this.getCachedCapabilityConfig()
3782
+ );
3783
+ const secretMaskingEnabled = typeof appliedMasking?.secretApplied === "boolean" ? appliedMasking.secretApplied : this.resolveEffectiveSecretMasking(
3784
+ capabilityConfig ?? this.getCachedCapabilityConfig()
3785
+ );
3656
3786
  return {
3657
3787
  capabilities: {
3658
3788
  has_feedback_handler: hasFeedbackHandler,
3659
- pii_masking_enabled: this.resolveEffectivePiiMasking(
3660
- capabilityConfig ?? this.getCachedCapabilityConfig()
3661
- ),
3662
- secret_masking_enabled: this.resolveEffectiveSecretMasking(
3663
- capabilityConfig ?? this.getCachedCapabilityConfig()
3664
- ),
3789
+ pii_masking_enabled: piiMaskingEnabled,
3790
+ secret_masking_enabled: secretMaskingEnabled,
3665
3791
  framework
3666
3792
  }
3667
3793
  };
@@ -3688,11 +3814,12 @@ var AgentID = class {
3688
3814
  return createEventId2();
3689
3815
  }
3690
3816
  buildGuardCacheKey(params, apiKey) {
3691
- if (!params.system_id || !params.input) {
3817
+ const cacheInputSource = typeof params.prompt_context === "string" && params.prompt_context.trim().length > 0 ? params.prompt_context : params.input;
3818
+ if (!params.system_id || !cacheInputSource) {
3692
3819
  return null;
3693
3820
  }
3694
3821
  const userId = params.user_id?.trim() ?? "";
3695
- const normalizedInput = params.input.trim().replace(/\s+/g, " ").slice(0, 2048);
3822
+ const normalizedInput = cacheInputSource.trim().replace(/\s+/g, " ").slice(0, 2048);
3696
3823
  const keyPrefix = apiKey?.slice(0, 24) ?? "";
3697
3824
  return `${keyPrefix}|${params.system_id}|${userId}|${normalizedInput.length}|${normalizedInput}`;
3698
3825
  }
@@ -3756,20 +3883,7 @@ var AgentID = class {
3756
3883
  return config.strict_security_mode || config.failure_mode === "fail_close";
3757
3884
  }
3758
3885
  buildFailOpenGuardVerdict(reason, input, options) {
3759
- const capabilityConfig = this.getCachedCapabilityConfig(options);
3760
- const shouldMaskPii = capabilityConfig.block_pii_leakage || this.resolveEffectivePiiMasking(capabilityConfig);
3761
- const shouldMaskSecrets = capabilityConfig.block_secret_leakage === true || this.resolveEffectiveSecretMasking(capabilityConfig);
3762
3886
  const response = { allowed: true, reason };
3763
- if (input && (shouldMaskPii || shouldMaskSecrets)) {
3764
- const masked = this.pii.anonymize(input, {
3765
- pii: shouldMaskPii,
3766
- secrets: shouldMaskSecrets
3767
- });
3768
- if (masked.maskedText !== input) {
3769
- response.transformed_input = masked.maskedText;
3770
- response.detected_pii = Object.keys(masked.mapping).length > 0;
3771
- }
3772
- }
3773
3887
  return response;
3774
3888
  }
3775
3889
  maybeRaiseStrictIngestDependencyError(params) {
@@ -3798,6 +3912,43 @@ var AgentID = class {
3798
3912
  }
3799
3913
  return config.block_on_heuristic;
3800
3914
  }
3915
+ buildInlineAttachmentPromptScanInput(attachments, maxChars = 6e3) {
3916
+ if (!Array.isArray(attachments) || attachments.length === 0) {
3917
+ return "";
3918
+ }
3919
+ const text = attachments.slice(0, 4).map((attachment) => {
3920
+ const attachmentText = typeof attachment?.text === "string" ? attachment.text.trim() : "";
3921
+ if (!attachmentText) {
3922
+ return "";
3923
+ }
3924
+ const filename = typeof attachment.filename === "string" && attachment.filename.trim().length > 0 ? attachment.filename.trim() : "attachment";
3925
+ return `[Attachment: ${filename}]
3926
+ ${attachmentText}`;
3927
+ }).filter(Boolean).join("\n\n");
3928
+ if (!text || text.length <= maxChars) {
3929
+ return text;
3930
+ }
3931
+ const headBudget = Math.max(256, Math.floor(maxChars * 0.55));
3932
+ const tailBudget = Math.max(128, maxChars - headBudget - 16);
3933
+ return `${text.slice(0, headBudget)}
3934
+
3935
+ [...]
3936
+
3937
+ ${text.slice(-tailBudget)}`;
3938
+ }
3939
+ buildPromptInjectionScanInput(params) {
3940
+ const source = typeof params.promptContext === "string" && params.promptContext.trim().length > 0 ? params.promptContext : params.input;
3941
+ const attachmentInput = this.buildInlineAttachmentPromptScanInput(params.attachments);
3942
+ if (!source) {
3943
+ return attachmentInput;
3944
+ }
3945
+ if (!attachmentInput) {
3946
+ return source;
3947
+ }
3948
+ return `${source}
3949
+
3950
+ ${attachmentInput}`;
3951
+ }
3801
3952
  async refreshCapabilityConfigBeforeClientControl(params) {
3802
3953
  const refreshed = await this.getCapabilityConfigWithTelemetry(true, params.options);
3803
3954
  return {
@@ -3807,9 +3958,14 @@ var AgentID = class {
3807
3958
  }
3808
3959
  async applyLocalPolicyChecks(params) {
3809
3960
  const localScanStartedAt = Date.now();
3810
- if (params.runPromptInjectionCheck && params.input && this.shouldRunLocalInjectionScan(params.capabilityConfig)) {
3961
+ const promptScanInput = this.buildPromptInjectionScanInput({
3962
+ input: params.input,
3963
+ promptContext: params.promptContext,
3964
+ capabilityConfig: params.capabilityConfig
3965
+ });
3966
+ if (params.runPromptInjectionCheck && promptScanInput && this.shouldRunLocalInjectionScan(params.capabilityConfig)) {
3811
3967
  await this.injectionScanner.scan({
3812
- prompt: params.input,
3968
+ prompt: promptScanInput,
3813
3969
  apiKey: params.apiKey,
3814
3970
  baseUrl: this.baseUrl,
3815
3971
  aiScanEnabled: this.aiScanEnabled,
@@ -3836,6 +3992,9 @@ var AgentID = class {
3836
3992
  });
3837
3993
  const sdkLocalScanMs = Math.max(0, Date.now() - localScanStartedAt);
3838
3994
  for (const event of enforced.events) {
3995
+ if (event.violationType === "PII_LEAKAGE_STRICT" && event.actionTaken === "REDACTED") {
3996
+ continue;
3997
+ }
3839
3998
  this.logSecurityPolicyViolation({
3840
3999
  systemId: params.systemId,
3841
4000
  violationType: event.violationType,
@@ -3847,7 +4006,9 @@ var AgentID = class {
3847
4006
  });
3848
4007
  }
3849
4008
  return {
3850
- sanitizedInput: enforced.sanitizedInput,
4009
+ sanitizedInput: enforced.events.some(
4010
+ (event) => event.violationType === "PII_LEAKAGE_STRICT" && event.actionTaken === "REDACTED"
4011
+ ) ? params.input : enforced.sanitizedInput,
3851
4012
  sdkLocalScanMs
3852
4013
  };
3853
4014
  } catch (error) {
@@ -3883,22 +4044,6 @@ var AgentID = class {
3883
4044
  sdkConfigFetchMs = refreshed.sdkConfigFetchMs;
3884
4045
  }
3885
4046
  if (!this.clientFastFail) {
3886
- const effectivePiiMasking2 = this.resolveEffectivePiiMasking(capabilityConfig);
3887
- const effectiveSecretMasking2 = this.resolveEffectiveSecretMasking(capabilityConfig);
3888
- if (!capabilityConfig.block_pii_leakage && effectivePiiMasking2 || !capabilityConfig.block_secret_leakage && effectiveSecretMasking2) {
3889
- const masked = this.pii.anonymize(sanitizedInput, {
3890
- pii: !capabilityConfig.block_pii_leakage && effectivePiiMasking2,
3891
- secrets: !capabilityConfig.block_secret_leakage && effectiveSecretMasking2
3892
- });
3893
- return {
3894
- sanitizedInput: masked.maskedText,
3895
- capabilityConfig,
3896
- sdkConfigFetchMs,
3897
- sdkLocalScanMs,
3898
- piiMapping: masked.mapping,
3899
- shouldDeanonymize: Object.keys(masked.mapping).length > 0
3900
- };
3901
- }
3902
4047
  return {
3903
4048
  sanitizedInput,
3904
4049
  capabilityConfig,
@@ -3915,6 +4060,7 @@ var AgentID = class {
3915
4060
  sdkConfigFetchMs = refreshedConfig.sdkConfigFetchMs;
3916
4061
  const enforced = await this.applyLocalPolicyChecks({
3917
4062
  input: params.input,
4063
+ promptContext: params.promptContext,
3918
4064
  systemId: params.systemId,
3919
4065
  stream: params.stream,
3920
4066
  capabilityConfig,
@@ -3926,22 +4072,6 @@ var AgentID = class {
3926
4072
  });
3927
4073
  sanitizedInput = enforced.sanitizedInput;
3928
4074
  sdkLocalScanMs = enforced.sdkLocalScanMs;
3929
- const effectivePiiMasking = this.resolveEffectivePiiMasking(capabilityConfig);
3930
- const effectiveSecretMasking = this.resolveEffectiveSecretMasking(capabilityConfig);
3931
- if (!capabilityConfig.block_pii_leakage && effectivePiiMasking || !capabilityConfig.block_secret_leakage && effectiveSecretMasking) {
3932
- const masked = this.pii.anonymize(sanitizedInput, {
3933
- pii: !capabilityConfig.block_pii_leakage && effectivePiiMasking,
3934
- secrets: !capabilityConfig.block_secret_leakage && effectiveSecretMasking
3935
- });
3936
- return {
3937
- sanitizedInput: masked.maskedText,
3938
- capabilityConfig,
3939
- sdkConfigFetchMs,
3940
- sdkLocalScanMs,
3941
- piiMapping: masked.mapping,
3942
- shouldDeanonymize: Object.keys(masked.mapping).length > 0
3943
- };
3944
- }
3945
4075
  return {
3946
4076
  sanitizedInput,
3947
4077
  capabilityConfig,
@@ -3962,6 +4092,7 @@ var AgentID = class {
3962
4092
  });
3963
4093
  const enforced = await this.applyLocalPolicyChecks({
3964
4094
  input: params.input,
4095
+ promptContext: params.promptContext,
3965
4096
  systemId: params.systemId,
3966
4097
  stream: params.stream,
3967
4098
  capabilityConfig: refreshedConfig.capabilityConfig,
@@ -3978,77 +4109,71 @@ var AgentID = class {
3978
4109
  sdkLocalScanMs: enforced.sdkLocalScanMs
3979
4110
  };
3980
4111
  }
4112
+ async runLocalPromptInjectionFallback(params, options) {
4113
+ const effectiveApiKey = this.resolveApiKey(options?.apiKey);
4114
+ const resolvedConfig = params.capabilityConfig && typeof params.sdkConfigFetchMs === "number" ? {
4115
+ capabilityConfig: params.capabilityConfig,
4116
+ sdkConfigFetchMs: params.sdkConfigFetchMs
4117
+ } : await this.getCapabilityConfigWithTelemetry(false, options);
4118
+ const refreshedConfig = await this.refreshCapabilityConfigBeforeClientControl({
4119
+ capabilityConfig: resolvedConfig.capabilityConfig,
4120
+ sdkConfigFetchMs: resolvedConfig.sdkConfigFetchMs,
4121
+ options
4122
+ });
4123
+ const localScanStartedAt = Date.now();
4124
+ const promptScanInput = this.buildPromptInjectionScanInput({
4125
+ input: params.input,
4126
+ promptContext: params.promptContext,
4127
+ capabilityConfig: refreshedConfig.capabilityConfig,
4128
+ attachments: params.attachments
4129
+ });
4130
+ if (promptScanInput && this.shouldRunLocalInjectionScan(refreshedConfig.capabilityConfig)) {
4131
+ await this.injectionScanner.scan({
4132
+ prompt: promptScanInput,
4133
+ apiKey: effectiveApiKey,
4134
+ baseUrl: this.baseUrl,
4135
+ aiScanEnabled: this.aiScanEnabled,
4136
+ storePii: this.storePii,
4137
+ piiManager: this.pii,
4138
+ source: "js_sdk",
4139
+ systemId: params.systemId,
4140
+ eventId: params.clientEventId,
4141
+ clientEventId: params.clientEventId,
4142
+ telemetryMetadata: mergeTelemetryContexts(
4143
+ params.telemetryMetadata,
4144
+ buildSdkTimingMetadata({
4145
+ sdkConfigFetchMs: refreshedConfig.sdkConfigFetchMs,
4146
+ sdkConfigVersion: refreshedConfig.capabilityConfig.version
4147
+ })
4148
+ )
4149
+ });
4150
+ }
4151
+ return {
4152
+ capabilityConfig: refreshedConfig.capabilityConfig,
4153
+ sdkConfigFetchMs: refreshedConfig.sdkConfigFetchMs,
4154
+ sdkLocalScanMs: Math.max(0, Date.now() - localScanStartedAt)
4155
+ };
4156
+ }
3981
4157
  async scanPromptInjection(input, options) {
3982
4158
  if (!input) {
3983
4159
  return;
3984
4160
  }
3985
- const initialConfig = await this.getCapabilityConfigWithTelemetry(
3986
- false,
4161
+ await this.runLocalPromptInjectionFallback(
4162
+ {
4163
+ input,
4164
+ attachments: options?.attachments,
4165
+ systemId: options?.systemId,
4166
+ clientEventId: options?.clientEventId
4167
+ },
3987
4168
  options
3988
4169
  );
3989
- const refreshedConfig = await this.refreshCapabilityConfigBeforeClientControl({
3990
- capabilityConfig: initialConfig.capabilityConfig,
3991
- sdkConfigFetchMs: initialConfig.sdkConfigFetchMs,
3992
- options
3993
- });
3994
- if (!this.shouldRunLocalInjectionScan(refreshedConfig.capabilityConfig)) {
3995
- return;
3996
- }
3997
- const effectiveApiKey = this.resolveApiKey(options?.apiKey);
3998
- await this.injectionScanner.scan({
3999
- prompt: input,
4000
- apiKey: effectiveApiKey,
4001
- baseUrl: this.baseUrl,
4002
- aiScanEnabled: this.aiScanEnabled,
4003
- storePii: this.storePii,
4004
- piiManager: this.pii,
4005
- source: "js_sdk",
4006
- systemId: options?.systemId,
4007
- eventId: options?.clientEventId,
4008
- clientEventId: options?.clientEventId,
4009
- telemetryMetadata: buildSdkTimingMetadata({
4010
- sdkConfigFetchMs: refreshedConfig.sdkConfigFetchMs,
4011
- sdkConfigVersion: refreshedConfig.capabilityConfig.version
4012
- })
4013
- });
4014
4170
  }
4015
- withMaskedOpenAIRequest(req, maskedText, options) {
4171
+ withMaskedOpenAIRequest(req, maskedText) {
4016
4172
  const messages = Array.isArray(req?.messages) ? req.messages : null;
4017
4173
  if (!messages) {
4018
4174
  return req;
4019
4175
  }
4020
- const newMessages = messages.map((message2) => {
4021
- if (!message2 || typeof message2 !== "object") {
4022
- return message2;
4023
- }
4024
- const typedMessage = message2;
4025
- const currentContent2 = typedMessage.content;
4026
- if (typeof currentContent2 === "string") {
4027
- return {
4028
- ...typedMessage,
4029
- content: this.pii.anonymize(currentContent2, options).maskedText
4030
- };
4031
- }
4032
- if (Array.isArray(currentContent2)) {
4033
- return {
4034
- ...typedMessage,
4035
- content: currentContent2.map((part) => {
4036
- if (!part || typeof part !== "object") {
4037
- return part;
4038
- }
4039
- const typedPart = part;
4040
- if (typeof typedPart.text !== "string") {
4041
- return part;
4042
- }
4043
- return {
4044
- ...typedPart,
4045
- text: this.pii.anonymize(typedPart.text, options).maskedText
4046
- };
4047
- })
4048
- };
4049
- }
4050
- return message2;
4051
- });
4176
+ const newMessages = messages.map((message2) => message2);
4052
4177
  let lastUserIdx = null;
4053
4178
  for (let i = 0; i < newMessages.length; i += 1) {
4054
4179
  const msg = newMessages[i];
@@ -4082,7 +4207,7 @@ var AgentID = class {
4082
4207
  text: maskedText
4083
4208
  });
4084
4209
  }
4085
- nextContent = textReplaced ? preservedParts : [{ type: "text", text: maskedText }, ...currentContent];
4210
+ nextContent = textReplaced ? preservedParts : maskedText.length > 0 ? [{ type: "text", text: maskedText }, ...currentContent] : currentContent;
4086
4211
  }
4087
4212
  newMessages[lastUserIdx] = {
4088
4213
  ...message,
@@ -4099,7 +4224,7 @@ var AgentID = class {
4099
4224
  logSecurityPolicyViolation(params) {
4100
4225
  this.log({
4101
4226
  system_id: params.systemId,
4102
- input: "[REDACTED_SAMPLE]",
4227
+ input: "[REDACTED]",
4103
4228
  output: "",
4104
4229
  model: "agentid.policy.enforcer",
4105
4230
  event_type: "security_policy_violation",
@@ -4110,7 +4235,7 @@ var AgentID = class {
4110
4235
  severity: "high",
4111
4236
  system_id: params.systemId,
4112
4237
  violation_type: params.violationType,
4113
- input_snippet: "[REDACTED_SAMPLE]",
4238
+ input_snippet: "[REDACTED]",
4114
4239
  action_taken: params.actionTaken,
4115
4240
  ...buildSdkTimingMetadata({
4116
4241
  sdkConfigFetchMs: params.sdkConfigFetchMs,
@@ -4123,17 +4248,19 @@ var AgentID = class {
4123
4248
  }, { apiKey: params.apiKey });
4124
4249
  }
4125
4250
  logGuardFallback(params) {
4251
+ const retainedInput = getZeroRetentionInput(params.guardParams.input, void 0);
4126
4252
  this.log(
4127
4253
  {
4128
4254
  system_id: params.guardParams.system_id,
4129
4255
  user_id: params.guardParams.user_id,
4130
- input: params.guardParams.input,
4256
+ input: retainedInput,
4131
4257
  output: "",
4132
4258
  model: params.guardParams.model ?? "unknown",
4133
4259
  event_type: "security_alert",
4134
4260
  severity: "warning",
4135
4261
  metadata: {
4136
4262
  ...params.guardParams.metadata ?? {},
4263
+ transformed_input: retainedInput,
4137
4264
  source: "guard",
4138
4265
  status: params.status,
4139
4266
  guard_reason: params.reason,
@@ -4627,11 +4754,12 @@ var AgentID = class {
4627
4754
  completion,
4628
4755
  options?.piiMapping
4629
4756
  );
4757
+ const transformedOutput = options?.deanonymizeForClient === true && options.piiMapping ? this.pii.deanonymize(completion, options.piiMapping) : masked.maskedText;
4630
4758
  return {
4631
4759
  mode: "static",
4632
4760
  rawOutput: completion,
4633
- transformedOutput: masked.maskedText,
4634
- outputMasked: masked.maskedText !== completion || placeholderOutputMasked
4761
+ transformedOutput,
4762
+ outputMasked: transformedOutput !== completion || placeholderOutputMasked
4635
4763
  };
4636
4764
  }
4637
4765
  if (!isAsyncIterable(completion)) {
@@ -4641,11 +4769,12 @@ var AgentID = class {
4641
4769
  asText,
4642
4770
  options?.piiMapping
4643
4771
  );
4772
+ const transformedOutput = options?.deanonymizeForClient === true && options.piiMapping ? this.pii.deanonymize(asText, options.piiMapping) : masked.maskedText;
4644
4773
  return {
4645
4774
  mode: "static",
4646
4775
  rawOutput: asText,
4647
- transformedOutput: masked.maskedText,
4648
- outputMasked: masked.maskedText !== asText || placeholderOutputMasked
4776
+ transformedOutput,
4777
+ outputMasked: transformedOutput !== asText || placeholderOutputMasked
4649
4778
  };
4650
4779
  }
4651
4780
  const source = completion;
@@ -4840,6 +4969,7 @@ var AgentID = class {
4840
4969
  */
4841
4970
  wrapOpenAI(openai, options) {
4842
4971
  const systemId = options.system_id;
4972
+ const deanonymizeOutputForClient = options.deanonymizeOutputForClient === true || options.deanonymize_output_for_client === true;
4843
4973
  const expectedLanguages = normalizeExpectedLanguages(
4844
4974
  options.expected_languages ?? options.expectedLanguages
4845
4975
  );
@@ -4880,38 +5010,48 @@ var AgentID = class {
4880
5010
  const stream = adapter.isStream(providerReq);
4881
5011
  let capabilityConfig = this.getCachedCapabilityConfig(requestOptions);
4882
5012
  const userText = adapter.extractInput(providerReq);
4883
- const requestAttachments = adapter.extractAttachments(providerReq);
5013
+ const rawPromptContext = adapter.extractPromptContext(providerReq);
5014
+ let requestAttachments = adapter.extractAttachments(providerReq);
4884
5015
  const hasGuardContent = userText !== null || requestAttachments.length > 0;
4885
5016
  let maskedText = userText ?? "";
4886
5017
  let maskedReq = providerReq;
4887
5018
  let createArgs = providerReq === rawReq ? normalizedCreateArgs : [{ ...providerReq }, ...normalizedCreateArgs.slice(1)];
4888
5019
  let mapping = {};
5020
+ let clientInputMaskingTelemetry = {
5021
+ piiApplied: false,
5022
+ secretApplied: false
5023
+ };
4889
5024
  let sdkConfigFetchMs = 0;
4890
5025
  let sdkLocalScanMs = 0;
4891
- let providerMaskingOptions;
4892
5026
  if (hasGuardContent) {
4893
5027
  const prepared = await this.prepareInputForDispatch({
4894
5028
  input: userText ?? "",
5029
+ promptContext: rawPromptContext ?? void 0,
4895
5030
  systemId,
4896
5031
  stream,
4897
5032
  clientEventId,
4898
5033
  telemetryMetadata
4899
5034
  }, requestOptions);
4900
5035
  capabilityConfig = prepared.capabilityConfig;
4901
- providerMaskingOptions = {
4902
- pii: !capabilityConfig.block_pii_leakage && this.resolveEffectivePiiMasking(capabilityConfig),
4903
- secrets: !capabilityConfig.block_secret_leakage && this.resolveEffectiveSecretMasking(capabilityConfig)
4904
- };
4905
5036
  maskedText = prepared.sanitizedInput;
4906
- mapping = prepared.piiMapping ?? {};
5037
+ const preparedPiiMapping = normalizePiiMapping(prepared.piiMapping);
5038
+ const preparedMaskingTelemetry = getMaskingTelemetryFromMapping(
5039
+ preparedPiiMapping
5040
+ );
5041
+ clientInputMaskingTelemetry = {
5042
+ piiApplied: preparedMaskingTelemetry.piiApplied || maskedText !== (userText ?? ""),
5043
+ secretApplied: preparedMaskingTelemetry.secretApplied
5044
+ };
5045
+ mapping = preparedPiiMapping ?? {};
4907
5046
  sdkConfigFetchMs = prepared.sdkConfigFetchMs ?? 0;
4908
5047
  sdkLocalScanMs = prepared.sdkLocalScanMs ?? 0;
4909
- if (maskedText !== (userText ?? "")) {
5048
+ const shouldProtectRequestHistory = maskedText !== (userText ?? "");
5049
+ if (shouldProtectRequestHistory) {
4910
5050
  maskedReq = this.withMaskedOpenAIRequest(
4911
5051
  providerReq,
4912
- maskedText,
4913
- providerMaskingOptions
5052
+ maskedText
4914
5053
  );
5054
+ requestAttachments = adapter.extractAttachments(maskedReq);
4915
5055
  const nextCreateArgs = [...createArgs];
4916
5056
  nextCreateArgs[0] = maskedReq;
4917
5057
  createArgs = nextCreateArgs;
@@ -4922,8 +5062,16 @@ var AgentID = class {
4922
5062
  "AgentID: No user message or supported inline attachment found. Security guard requires prompt content."
4923
5063
  );
4924
5064
  }
5065
+ const promptContextForGuard = adapter.extractPromptContext(maskedReq) ?? rawPromptContext ?? void 0;
5066
+ const clientCapabilities = this.buildClientCapabilities(
5067
+ "openai",
5068
+ false,
5069
+ capabilityConfig,
5070
+ clientInputMaskingTelemetry
5071
+ );
4925
5072
  const verdict = await this.guard({
4926
5073
  input: maskedText,
5074
+ prompt_context: promptContextForGuard,
4927
5075
  system_id: systemId,
4928
5076
  model: adapter.getModelName(maskedReq),
4929
5077
  user_id: options.user_id,
@@ -4932,63 +5080,54 @@ var AgentID = class {
4932
5080
  request_identity: options.request_identity,
4933
5081
  metadata: telemetryMetadata,
4934
5082
  attachments: requestAttachments,
4935
- client_capabilities: this.buildClientCapabilities(
4936
- "openai",
4937
- false,
4938
- capabilityConfig
4939
- )
5083
+ client_capabilities: clientCapabilities
4940
5084
  }, requestOptions);
4941
5085
  let localFallbackApplied = false;
4942
5086
  let localFallbackReason = null;
4943
5087
  if (!verdict.allowed) {
4944
- if (effectiveStrictMode && isGuardFailureEligibleForLocalFallback(verdict.reason)) {
4945
- localFallbackApplied = true;
4946
- localFallbackReason = verdict.reason ?? "guard_unreachable";
4947
- if (sdkLocalScanMs === 0) {
4948
- const fallback = await this.applyLocalPolicyChecks({
4949
- input: maskedText,
4950
- systemId,
4951
- stream,
4952
- capabilityConfig,
4953
- apiKey: effectiveApiKey,
4954
- clientEventId,
4955
- sdkConfigFetchMs,
4956
- telemetryMetadata,
4957
- runPromptInjectionCheck: true
4958
- });
4959
- maskedText = fallback.sanitizedInput;
4960
- sdkLocalScanMs = fallback.sdkLocalScanMs;
4961
- }
4962
- } else {
4963
- await this.logPromptPreflightStep(
4964
- {
4965
- system_id: systemId,
4966
- user_id: options.user_id,
4967
- request_identity: options.request_identity,
4968
- input: maskedText,
4969
- telemetry: telemetryMetadata,
4970
- verdict,
4971
- guard_event_id: verdict.guard_event_id ?? null,
4972
- 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),
4973
- preflight_for_client_event_id: typeof verdict.client_event_id === "string" && isUuidLike2(verdict.client_event_id) ? verdict.client_event_id : clientEventId,
4974
- client_capabilities: this.buildClientCapabilities(
4975
- "openai",
4976
- false,
4977
- capabilityConfig
4978
- ),
4979
- runtime_surface: "openai_sdk_guard"
4980
- },
4981
- requestOptions
4982
- );
4983
- throw new SecurityBlockError(verdict.reason ?? "guard_denied");
4984
- }
5088
+ await this.logPromptPreflightStep(
5089
+ {
5090
+ system_id: systemId,
5091
+ user_id: options.user_id,
5092
+ request_identity: options.request_identity,
5093
+ input: getZeroRetentionInput(userText ?? "", maskedText),
5094
+ telemetry: telemetryMetadata,
5095
+ verdict,
5096
+ guard_event_id: verdict.guard_event_id ?? null,
5097
+ 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),
5098
+ preflight_for_client_event_id: typeof verdict.client_event_id === "string" && isUuidLike2(verdict.client_event_id) ? verdict.client_event_id : clientEventId,
5099
+ client_capabilities: clientCapabilities,
5100
+ runtime_surface: "openai_sdk_guard"
5101
+ },
5102
+ requestOptions
5103
+ );
5104
+ throw new SecurityBlockError(verdict.reason ?? "guard_denied");
5105
+ }
5106
+ if (isFailOpenGuardBypassReason(verdict.reason)) {
5107
+ const fallback = await this.runLocalPromptInjectionFallback(
5108
+ {
5109
+ input: userText ?? "",
5110
+ promptContext: rawPromptContext ?? void 0,
5111
+ attachments: requestAttachments,
5112
+ systemId,
5113
+ clientEventId,
5114
+ capabilityConfig,
5115
+ sdkConfigFetchMs,
5116
+ telemetryMetadata
5117
+ },
5118
+ requestOptions
5119
+ );
5120
+ capabilityConfig = fallback.capabilityConfig;
5121
+ sdkConfigFetchMs = fallback.sdkConfigFetchMs;
5122
+ sdkLocalScanMs += fallback.sdkLocalScanMs;
5123
+ localFallbackApplied = true;
5124
+ localFallbackReason = verdict.reason ?? null;
4985
5125
  }
4986
5126
  const currentRequestInput = adapter.extractInput(maskedReq) ?? "";
4987
- if (maskedText !== currentRequestInput || providerMaskingOptions?.pii === true || providerMaskingOptions?.secrets === true) {
5127
+ if (maskedText !== currentRequestInput) {
4988
5128
  maskedReq = this.withMaskedOpenAIRequest(
4989
5129
  providerReq,
4990
- maskedText,
4991
- providerMaskingOptions
5130
+ maskedText
4992
5131
  );
4993
5132
  const nextCreateArgs = [...createArgs];
4994
5133
  nextCreateArgs[0] = maskedReq;
@@ -5011,29 +5150,29 @@ var AgentID = class {
5011
5150
  maskedText = transformedInput;
5012
5151
  maskedReq = this.withMaskedOpenAIRequest(
5013
5152
  providerReq,
5014
- transformedInput,
5015
- providerMaskingOptions
5153
+ transformedInput
5016
5154
  );
5017
5155
  const nextCreateArgs = [...createArgs];
5018
5156
  nextCreateArgs[0] = maskedReq;
5019
5157
  createArgs = nextCreateArgs;
5020
5158
  }
5159
+ const shouldDeanonymizeForClient = deanonymizeOutputForClient && !isShadowMode && Object.keys(mapping).length > 0;
5160
+ const retainedInputForLogs = getZeroRetentionInput(
5161
+ userText ?? "",
5162
+ maskedText
5163
+ );
5021
5164
  await this.logPromptPreflightStep(
5022
5165
  {
5023
5166
  system_id: systemId,
5024
5167
  user_id: options.user_id,
5025
5168
  request_identity: options.request_identity,
5026
- input: maskedText,
5169
+ input: retainedInputForLogs,
5027
5170
  telemetry: telemetryMetadata,
5028
5171
  verdict,
5029
5172
  guard_event_id: guardEventId,
5030
5173
  guard_latency_ms: guardLatencyMs,
5031
5174
  preflight_for_client_event_id: canonicalClientEventId,
5032
- client_capabilities: this.buildClientCapabilities(
5033
- "openai",
5034
- false,
5035
- capabilityConfig
5036
- ),
5175
+ client_capabilities: clientCapabilities,
5037
5176
  local_fallback_applied: localFallbackApplied,
5038
5177
  local_fallback_reason: localFallbackReason,
5039
5178
  runtime_surface: "openai_sdk_guard"
@@ -5051,12 +5190,13 @@ var AgentID = class {
5051
5190
  })(),
5052
5191
  {
5053
5192
  piiMapping: mapping,
5054
- deanonymizeForClient: false,
5055
- maskForClient: !isShadowMode
5193
+ deanonymizeForClient: shouldDeanonymizeForClient,
5194
+ maskForClient: !isShadowMode && !shouldDeanonymizeForClient
5056
5195
  }
5057
5196
  );
5058
5197
  if (maskedText && wrappedCompletion.mode === "stream") {
5059
5198
  void wrappedCompletion.done.then(async (result) => {
5199
+ const effectiveInputMaskingTelemetry = getMaskingTelemetryFromMapping(mapping);
5060
5200
  const modelLatencyMs2 = Math.max(0, Date.now() - modelStartedAt2);
5061
5201
  const totalPipelineLatencyMs2 = Math.max(0, Date.now() - pipelineStartedAt);
5062
5202
  const outputForLog = result.transformedOutput;
@@ -5065,7 +5205,7 @@ var AgentID = class {
5065
5205
  system_id: systemId,
5066
5206
  user_id: options.user_id,
5067
5207
  request_identity: options.request_identity,
5068
- input: maskedText,
5208
+ input: retainedInputForLogs,
5069
5209
  output: outputForLog,
5070
5210
  model: adapter.getModelName(maskedReq),
5071
5211
  usage: result.usage,
@@ -5074,9 +5214,17 @@ var AgentID = class {
5074
5214
  metadata: mergeTelemetryContexts(
5075
5215
  telemetryMetadata,
5076
5216
  {
5077
- transformed_input: maskedText,
5217
+ transformed_input: retainedInputForLogs,
5078
5218
  transformed_output: result.transformedOutput,
5079
5219
  output_masked: result.outputMasked,
5220
+ client_side_pii_masking_applied: clientInputMaskingTelemetry.piiApplied,
5221
+ client_side_secret_masking_applied: clientInputMaskingTelemetry.secretApplied,
5222
+ server_side_pii_masking_applied: effectiveInputMaskingTelemetry.piiApplied && !clientInputMaskingTelemetry.piiApplied,
5223
+ server_side_secret_masking_applied: effectiveInputMaskingTelemetry.secretApplied && !clientInputMaskingTelemetry.secretApplied,
5224
+ effective_pii_masking_applied: effectiveInputMaskingTelemetry.piiApplied,
5225
+ effective_secret_masking_applied: effectiveInputMaskingTelemetry.secretApplied,
5226
+ effective_input_was_transformed: retainedInputForLogs !== "[REDACTED]",
5227
+ effective_output_was_transformed: result.outputMasked,
5080
5228
  shadow_mode: isShadowMode,
5081
5229
  simulated_decision: verdict.simulated_decision ?? null,
5082
5230
  simulated_output_decision: isShadowMode && result.outputMasked ? "masked" : "allowed",
@@ -5097,11 +5245,7 @@ var AgentID = class {
5097
5245
  sdkConfigVersion: capabilityConfig.version
5098
5246
  })
5099
5247
  ),
5100
- client_capabilities: this.buildClientCapabilities(
5101
- "openai",
5102
- false,
5103
- capabilityConfig
5104
- )
5248
+ client_capabilities: clientCapabilities
5105
5249
  }, requestOptions);
5106
5250
  if (!ingestResult.ok) {
5107
5251
  this.maybeRaiseStrictIngestDependencyError({
@@ -5126,6 +5270,7 @@ var AgentID = class {
5126
5270
  const modelLatencyMs = Math.max(0, Date.now() - modelStartedAt);
5127
5271
  const totalPipelineLatencyMs = Math.max(0, Date.now() - pipelineStartedAt);
5128
5272
  if (maskedText) {
5273
+ const effectiveInputMaskingTelemetry = getMaskingTelemetryFromMapping(mapping);
5129
5274
  const output = adapter.extractOutput(res);
5130
5275
  const wrappedCompletion = this.wrapCompletion(output, {
5131
5276
  piiMapping: mapping,
@@ -5139,7 +5284,7 @@ var AgentID = class {
5139
5284
  system_id: systemId,
5140
5285
  user_id: options.user_id,
5141
5286
  request_identity: options.request_identity,
5142
- input: maskedText,
5287
+ input: retainedInputForLogs,
5143
5288
  output: outputForLog,
5144
5289
  model,
5145
5290
  usage,
@@ -5148,9 +5293,17 @@ var AgentID = class {
5148
5293
  metadata: mergeTelemetryContexts(
5149
5294
  telemetryMetadata,
5150
5295
  {
5151
- transformed_input: maskedText,
5296
+ transformed_input: retainedInputForLogs,
5152
5297
  transformed_output: wrappedCompletion.transformedOutput,
5153
5298
  output_masked: wrappedCompletion.outputMasked,
5299
+ client_side_pii_masking_applied: clientInputMaskingTelemetry.piiApplied,
5300
+ client_side_secret_masking_applied: clientInputMaskingTelemetry.secretApplied,
5301
+ server_side_pii_masking_applied: effectiveInputMaskingTelemetry.piiApplied && !clientInputMaskingTelemetry.piiApplied,
5302
+ server_side_secret_masking_applied: effectiveInputMaskingTelemetry.secretApplied && !clientInputMaskingTelemetry.secretApplied,
5303
+ effective_pii_masking_applied: effectiveInputMaskingTelemetry.piiApplied,
5304
+ effective_secret_masking_applied: effectiveInputMaskingTelemetry.secretApplied,
5305
+ effective_input_was_transformed: retainedInputForLogs !== "[REDACTED]",
5306
+ effective_output_was_transformed: wrappedCompletion.outputMasked,
5154
5307
  shadow_mode: isShadowMode,
5155
5308
  simulated_decision: verdict.simulated_decision ?? null,
5156
5309
  simulated_output_decision: isShadowMode && wrappedCompletion.outputMasked ? "masked" : "allowed",
@@ -5171,11 +5324,7 @@ var AgentID = class {
5171
5324
  sdkConfigVersion: capabilityConfig.version
5172
5325
  })
5173
5326
  ),
5174
- client_capabilities: this.buildClientCapabilities(
5175
- "openai",
5176
- false,
5177
- capabilityConfig
5178
- )
5327
+ client_capabilities: clientCapabilities
5179
5328
  }, requestOptions);
5180
5329
  if (!ingestResult.ok) {
5181
5330
  this.maybeRaiseStrictIngestDependencyError({
@@ -5189,7 +5338,7 @@ var AgentID = class {
5189
5338
  }
5190
5339
  if (!isShadowMode && maskedText) {
5191
5340
  const output = adapter.extractOutput(res);
5192
- const maskedOutput = this.wrapCompletion(output, {
5341
+ const clientFacingOutput = shouldDeanonymizeForClient ? this.pii.deanonymize(String(output ?? ""), mapping) : this.wrapCompletion(output, {
5193
5342
  piiMapping: mapping,
5194
5343
  deanonymizeForClient: false
5195
5344
  }).transformedOutput;
@@ -5198,10 +5347,10 @@ var AgentID = class {
5198
5347
  for (const choice of res.choices) {
5199
5348
  const typedChoice = choice;
5200
5349
  if (typedChoice?.message && typeof typedChoice.message.content === "string") {
5201
- typedChoice.message.content = maskedOutput;
5350
+ typedChoice.message.content = clientFacingOutput;
5202
5351
  }
5203
5352
  if (typedChoice?.delta && typeof typedChoice.delta.content === "string") {
5204
- typedChoice.delta.content = maskedOutput;
5353
+ typedChoice.delta.content = clientFacingOutput;
5205
5354
  }
5206
5355
  }
5207
5356
  }
@@ -5386,13 +5535,15 @@ function protectMessageHistory(messages, options = { pii: true, secrets: true })
5386
5535
  const piiManager = new PIIManager();
5387
5536
  let textPartsCount = 0;
5388
5537
  let transformedTextPartsCount = 0;
5538
+ const placeholderMapping = {};
5389
5539
  const protectString = (value) => {
5390
5540
  textPartsCount += 1;
5391
- const masked = piiManager.anonymize(value, options).maskedText;
5392
- if (masked !== value) {
5541
+ const masked = piiManager.anonymize(value, options);
5542
+ Object.assign(placeholderMapping, masked.mapping);
5543
+ if (masked.maskedText !== value) {
5393
5544
  transformedTextPartsCount += 1;
5394
5545
  }
5395
- return masked;
5546
+ return masked.maskedText;
5396
5547
  };
5397
5548
  const visit = (value, key) => {
5398
5549
  if (typeof value === "string") {
@@ -5424,7 +5575,31 @@ function protectMessageHistory(messages, options = { pii: true, secrets: true })
5424
5575
  messages: protectedMessages,
5425
5576
  transformed: protectedMessages !== messages,
5426
5577
  textPartsCount,
5427
- transformedTextPartsCount
5578
+ transformedTextPartsCount,
5579
+ placeholderMapping
5580
+ };
5581
+ }
5582
+ function protectChatState(messages, options = {}) {
5583
+ const transcript = {
5584
+ ui: options.transcript?.ui ?? "masked",
5585
+ provider: options.transcript?.provider ?? "masked",
5586
+ persistence: options.transcript?.persistence ?? "masked"
5587
+ };
5588
+ const protectedHistory = protectMessageHistory(messages, {
5589
+ pii: options.pii ?? true,
5590
+ secrets: options.secrets ?? true
5591
+ });
5592
+ const maskedMessages = protectedHistory.messages;
5593
+ return {
5594
+ rawMessages: messages,
5595
+ uiMessages: transcript.ui === "masked" ? maskedMessages : messages,
5596
+ providerMessages: transcript.provider === "masked" ? maskedMessages : messages,
5597
+ persistenceMessages: transcript.persistence === "masked" ? maskedMessages : messages,
5598
+ transformed: protectedHistory.transformed,
5599
+ textPartsCount: protectedHistory.textPartsCount,
5600
+ transformedTextPartsCount: protectedHistory.transformedTextPartsCount,
5601
+ placeholderMapping: protectedHistory.placeholderMapping,
5602
+ transcript
5428
5603
  };
5429
5604
  }
5430
5605
  // Annotate the CommonJS export names for ESM import in node:
@@ -5442,6 +5617,7 @@ function protectMessageHistory(messages, options = { pii: true, secrets: true })
5442
5617
  createAgentIdTelemetryContext,
5443
5618
  createAgentIdWorkflowTrail,
5444
5619
  getInjectionScanner,
5620
+ protectChatState,
5445
5621
  protectMessageHistory,
5446
5622
  scanWithRegex
5447
5623
  });