agentid-sdk 0.1.40 → 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.40".trim().length > 0 ? "js-0.1.40" : 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,
@@ -2748,7 +2841,7 @@ var GUARD_MAX_ATTEMPTS = 3;
2748
2841
  var GUARD_RETRY_DELAYS_MS = [250, 500];
2749
2842
  var INGEST_MAX_ATTEMPTS = 3;
2750
2843
  var INGEST_RETRY_DELAYS_MS = [250, 500];
2751
- var GUARD_VERDICT_CACHE_TTL_MS = 0;
2844
+ var GUARD_VERDICT_CACHE_TTL_MS = 1500;
2752
2845
  var MAX_INGEST_TEXT_CHARS = 32e3;
2753
2846
  var OPENAI_TELEMETRY_FIELD = "agentid_telemetry";
2754
2847
  function normalizeBaseUrl3(baseUrl) {
@@ -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})`);
@@ -3596,6 +3720,7 @@ var AgentID = class {
3596
3720
  constructor(config = {}) {
3597
3721
  this.injectionScanner = getInjectionScanner();
3598
3722
  this.recentGuardVerdicts = /* @__PURE__ */ new Map();
3723
+ this.pendingGuardRequests = /* @__PURE__ */ new Map();
3599
3724
  this.apiKey = resolveConfiguredApiKey(config.apiKey);
3600
3725
  this.baseUrl = normalizeBaseUrl3(config.baseUrl ?? "https://app.getagentid.com/api/v1");
3601
3726
  this.configuredPiiMasking = typeof config.piiMasking === "boolean" ? config.piiMasking : null;
@@ -3651,16 +3776,18 @@ var AgentID = class {
3651
3776
  getEffectiveSecretMaskingForConfig(capabilityConfig) {
3652
3777
  return this.resolveEffectiveSecretMasking(capabilityConfig);
3653
3778
  }
3654
- 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
+ );
3655
3786
  return {
3656
3787
  capabilities: {
3657
3788
  has_feedback_handler: hasFeedbackHandler,
3658
- pii_masking_enabled: this.resolveEffectivePiiMasking(
3659
- capabilityConfig ?? this.getCachedCapabilityConfig()
3660
- ),
3661
- secret_masking_enabled: this.resolveEffectiveSecretMasking(
3662
- capabilityConfig ?? this.getCachedCapabilityConfig()
3663
- ),
3789
+ pii_masking_enabled: piiMaskingEnabled,
3790
+ secret_masking_enabled: secretMaskingEnabled,
3664
3791
  framework
3665
3792
  }
3666
3793
  };
@@ -3686,13 +3813,15 @@ var AgentID = class {
3686
3813
  }
3687
3814
  return createEventId2();
3688
3815
  }
3689
- buildGuardCacheKey(params) {
3690
- if (!params.system_id || !params.input) {
3816
+ buildGuardCacheKey(params, apiKey) {
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) {
3691
3819
  return null;
3692
3820
  }
3693
3821
  const userId = params.user_id?.trim() ?? "";
3694
- const normalizedInput = params.input.slice(0, 2048);
3695
- return `${params.system_id}|${userId}|${normalizedInput.length}|${normalizedInput}`;
3822
+ const normalizedInput = cacheInputSource.trim().replace(/\s+/g, " ").slice(0, 2048);
3823
+ const keyPrefix = apiKey?.slice(0, 24) ?? "";
3824
+ return `${keyPrefix}|${params.system_id}|${userId}|${normalizedInput.length}|${normalizedInput}`;
3696
3825
  }
3697
3826
  readCachedGuardVerdict(cacheKey) {
3698
3827
  if (!cacheKey) return null;
@@ -3705,7 +3834,7 @@ var AgentID = class {
3705
3834
  return cached.verdict;
3706
3835
  }
3707
3836
  cacheGuardVerdict(cacheKey, verdict) {
3708
- if (!cacheKey || !verdict.allowed || GUARD_VERDICT_CACHE_TTL_MS <= 0) {
3837
+ if (!cacheKey || GUARD_VERDICT_CACHE_TTL_MS <= 0) {
3709
3838
  return;
3710
3839
  }
3711
3840
  this.recentGuardVerdicts.set(cacheKey, {
@@ -3754,20 +3883,7 @@ var AgentID = class {
3754
3883
  return config.strict_security_mode || config.failure_mode === "fail_close";
3755
3884
  }
3756
3885
  buildFailOpenGuardVerdict(reason, input, options) {
3757
- const capabilityConfig = this.getCachedCapabilityConfig(options);
3758
- const shouldMaskPii = capabilityConfig.block_pii_leakage || this.resolveEffectivePiiMasking(capabilityConfig);
3759
- const shouldMaskSecrets = capabilityConfig.block_secret_leakage === true || this.resolveEffectiveSecretMasking(capabilityConfig);
3760
3886
  const response = { allowed: true, reason };
3761
- if (input && (shouldMaskPii || shouldMaskSecrets)) {
3762
- const masked = this.pii.anonymize(input, {
3763
- pii: shouldMaskPii,
3764
- secrets: shouldMaskSecrets
3765
- });
3766
- if (masked.maskedText !== input) {
3767
- response.transformed_input = masked.maskedText;
3768
- response.detected_pii = Object.keys(masked.mapping).length > 0;
3769
- }
3770
- }
3771
3887
  return response;
3772
3888
  }
3773
3889
  maybeRaiseStrictIngestDependencyError(params) {
@@ -3796,6 +3912,43 @@ var AgentID = class {
3796
3912
  }
3797
3913
  return config.block_on_heuristic;
3798
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
+ }
3799
3952
  async refreshCapabilityConfigBeforeClientControl(params) {
3800
3953
  const refreshed = await this.getCapabilityConfigWithTelemetry(true, params.options);
3801
3954
  return {
@@ -3805,9 +3958,14 @@ var AgentID = class {
3805
3958
  }
3806
3959
  async applyLocalPolicyChecks(params) {
3807
3960
  const localScanStartedAt = Date.now();
3808
- 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)) {
3809
3967
  await this.injectionScanner.scan({
3810
- prompt: params.input,
3968
+ prompt: promptScanInput,
3811
3969
  apiKey: params.apiKey,
3812
3970
  baseUrl: this.baseUrl,
3813
3971
  aiScanEnabled: this.aiScanEnabled,
@@ -3834,6 +3992,9 @@ var AgentID = class {
3834
3992
  });
3835
3993
  const sdkLocalScanMs = Math.max(0, Date.now() - localScanStartedAt);
3836
3994
  for (const event of enforced.events) {
3995
+ if (event.violationType === "PII_LEAKAGE_STRICT" && event.actionTaken === "REDACTED") {
3996
+ continue;
3997
+ }
3837
3998
  this.logSecurityPolicyViolation({
3838
3999
  systemId: params.systemId,
3839
4000
  violationType: event.violationType,
@@ -3845,7 +4006,9 @@ var AgentID = class {
3845
4006
  });
3846
4007
  }
3847
4008
  return {
3848
- sanitizedInput: enforced.sanitizedInput,
4009
+ sanitizedInput: enforced.events.some(
4010
+ (event) => event.violationType === "PII_LEAKAGE_STRICT" && event.actionTaken === "REDACTED"
4011
+ ) ? params.input : enforced.sanitizedInput,
3849
4012
  sdkLocalScanMs
3850
4013
  };
3851
4014
  } catch (error) {
@@ -3881,22 +4044,6 @@ var AgentID = class {
3881
4044
  sdkConfigFetchMs = refreshed.sdkConfigFetchMs;
3882
4045
  }
3883
4046
  if (!this.clientFastFail) {
3884
- const effectivePiiMasking2 = this.resolveEffectivePiiMasking(capabilityConfig);
3885
- const effectiveSecretMasking2 = this.resolveEffectiveSecretMasking(capabilityConfig);
3886
- if (!capabilityConfig.block_pii_leakage && effectivePiiMasking2 || !capabilityConfig.block_secret_leakage && effectiveSecretMasking2) {
3887
- const masked = this.pii.anonymize(sanitizedInput, {
3888
- pii: !capabilityConfig.block_pii_leakage && effectivePiiMasking2,
3889
- secrets: !capabilityConfig.block_secret_leakage && effectiveSecretMasking2
3890
- });
3891
- return {
3892
- sanitizedInput: masked.maskedText,
3893
- capabilityConfig,
3894
- sdkConfigFetchMs,
3895
- sdkLocalScanMs,
3896
- piiMapping: masked.mapping,
3897
- shouldDeanonymize: Object.keys(masked.mapping).length > 0
3898
- };
3899
- }
3900
4047
  return {
3901
4048
  sanitizedInput,
3902
4049
  capabilityConfig,
@@ -3913,6 +4060,7 @@ var AgentID = class {
3913
4060
  sdkConfigFetchMs = refreshedConfig.sdkConfigFetchMs;
3914
4061
  const enforced = await this.applyLocalPolicyChecks({
3915
4062
  input: params.input,
4063
+ promptContext: params.promptContext,
3916
4064
  systemId: params.systemId,
3917
4065
  stream: params.stream,
3918
4066
  capabilityConfig,
@@ -3924,22 +4072,6 @@ var AgentID = class {
3924
4072
  });
3925
4073
  sanitizedInput = enforced.sanitizedInput;
3926
4074
  sdkLocalScanMs = enforced.sdkLocalScanMs;
3927
- const effectivePiiMasking = this.resolveEffectivePiiMasking(capabilityConfig);
3928
- const effectiveSecretMasking = this.resolveEffectiveSecretMasking(capabilityConfig);
3929
- if (!capabilityConfig.block_pii_leakage && effectivePiiMasking || !capabilityConfig.block_secret_leakage && effectiveSecretMasking) {
3930
- const masked = this.pii.anonymize(sanitizedInput, {
3931
- pii: !capabilityConfig.block_pii_leakage && effectivePiiMasking,
3932
- secrets: !capabilityConfig.block_secret_leakage && effectiveSecretMasking
3933
- });
3934
- return {
3935
- sanitizedInput: masked.maskedText,
3936
- capabilityConfig,
3937
- sdkConfigFetchMs,
3938
- sdkLocalScanMs,
3939
- piiMapping: masked.mapping,
3940
- shouldDeanonymize: Object.keys(masked.mapping).length > 0
3941
- };
3942
- }
3943
4075
  return {
3944
4076
  sanitizedInput,
3945
4077
  capabilityConfig,
@@ -3960,6 +4092,7 @@ var AgentID = class {
3960
4092
  });
3961
4093
  const enforced = await this.applyLocalPolicyChecks({
3962
4094
  input: params.input,
4095
+ promptContext: params.promptContext,
3963
4096
  systemId: params.systemId,
3964
4097
  stream: params.stream,
3965
4098
  capabilityConfig: refreshedConfig.capabilityConfig,
@@ -3976,77 +4109,71 @@ var AgentID = class {
3976
4109
  sdkLocalScanMs: enforced.sdkLocalScanMs
3977
4110
  };
3978
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
+ }
3979
4157
  async scanPromptInjection(input, options) {
3980
4158
  if (!input) {
3981
4159
  return;
3982
4160
  }
3983
- const initialConfig = await this.getCapabilityConfigWithTelemetry(
3984
- false,
4161
+ await this.runLocalPromptInjectionFallback(
4162
+ {
4163
+ input,
4164
+ attachments: options?.attachments,
4165
+ systemId: options?.systemId,
4166
+ clientEventId: options?.clientEventId
4167
+ },
3985
4168
  options
3986
4169
  );
3987
- const refreshedConfig = await this.refreshCapabilityConfigBeforeClientControl({
3988
- capabilityConfig: initialConfig.capabilityConfig,
3989
- sdkConfigFetchMs: initialConfig.sdkConfigFetchMs,
3990
- options
3991
- });
3992
- if (!this.shouldRunLocalInjectionScan(refreshedConfig.capabilityConfig)) {
3993
- return;
3994
- }
3995
- const effectiveApiKey = this.resolveApiKey(options?.apiKey);
3996
- await this.injectionScanner.scan({
3997
- prompt: input,
3998
- apiKey: effectiveApiKey,
3999
- baseUrl: this.baseUrl,
4000
- aiScanEnabled: this.aiScanEnabled,
4001
- storePii: this.storePii,
4002
- piiManager: this.pii,
4003
- source: "js_sdk",
4004
- systemId: options?.systemId,
4005
- eventId: options?.clientEventId,
4006
- clientEventId: options?.clientEventId,
4007
- telemetryMetadata: buildSdkTimingMetadata({
4008
- sdkConfigFetchMs: refreshedConfig.sdkConfigFetchMs,
4009
- sdkConfigVersion: refreshedConfig.capabilityConfig.version
4010
- })
4011
- });
4012
4170
  }
4013
- withMaskedOpenAIRequest(req, maskedText, options) {
4171
+ withMaskedOpenAIRequest(req, maskedText) {
4014
4172
  const messages = Array.isArray(req?.messages) ? req.messages : null;
4015
4173
  if (!messages) {
4016
4174
  return req;
4017
4175
  }
4018
- const newMessages = messages.map((message2) => {
4019
- if (!message2 || typeof message2 !== "object") {
4020
- return message2;
4021
- }
4022
- const typedMessage = message2;
4023
- const currentContent2 = typedMessage.content;
4024
- if (typeof currentContent2 === "string") {
4025
- return {
4026
- ...typedMessage,
4027
- content: this.pii.anonymize(currentContent2, options).maskedText
4028
- };
4029
- }
4030
- if (Array.isArray(currentContent2)) {
4031
- return {
4032
- ...typedMessage,
4033
- content: currentContent2.map((part) => {
4034
- if (!part || typeof part !== "object") {
4035
- return part;
4036
- }
4037
- const typedPart = part;
4038
- if (typeof typedPart.text !== "string") {
4039
- return part;
4040
- }
4041
- return {
4042
- ...typedPart,
4043
- text: this.pii.anonymize(typedPart.text, options).maskedText
4044
- };
4045
- })
4046
- };
4047
- }
4048
- return message2;
4049
- });
4176
+ const newMessages = messages.map((message2) => message2);
4050
4177
  let lastUserIdx = null;
4051
4178
  for (let i = 0; i < newMessages.length; i += 1) {
4052
4179
  const msg = newMessages[i];
@@ -4080,7 +4207,7 @@ var AgentID = class {
4080
4207
  text: maskedText
4081
4208
  });
4082
4209
  }
4083
- nextContent = textReplaced ? preservedParts : [{ type: "text", text: maskedText }, ...currentContent];
4210
+ nextContent = textReplaced ? preservedParts : maskedText.length > 0 ? [{ type: "text", text: maskedText }, ...currentContent] : currentContent;
4084
4211
  }
4085
4212
  newMessages[lastUserIdx] = {
4086
4213
  ...message,
@@ -4097,7 +4224,7 @@ var AgentID = class {
4097
4224
  logSecurityPolicyViolation(params) {
4098
4225
  this.log({
4099
4226
  system_id: params.systemId,
4100
- input: "[REDACTED_SAMPLE]",
4227
+ input: "[REDACTED]",
4101
4228
  output: "",
4102
4229
  model: "agentid.policy.enforcer",
4103
4230
  event_type: "security_policy_violation",
@@ -4108,7 +4235,7 @@ var AgentID = class {
4108
4235
  severity: "high",
4109
4236
  system_id: params.systemId,
4110
4237
  violation_type: params.violationType,
4111
- input_snippet: "[REDACTED_SAMPLE]",
4238
+ input_snippet: "[REDACTED]",
4112
4239
  action_taken: params.actionTaken,
4113
4240
  ...buildSdkTimingMetadata({
4114
4241
  sdkConfigFetchMs: params.sdkConfigFetchMs,
@@ -4121,17 +4248,19 @@ var AgentID = class {
4121
4248
  }, { apiKey: params.apiKey });
4122
4249
  }
4123
4250
  logGuardFallback(params) {
4251
+ const retainedInput = getZeroRetentionInput(params.guardParams.input, void 0);
4124
4252
  this.log(
4125
4253
  {
4126
4254
  system_id: params.guardParams.system_id,
4127
4255
  user_id: params.guardParams.user_id,
4128
- input: params.guardParams.input,
4256
+ input: retainedInput,
4129
4257
  output: "",
4130
4258
  model: params.guardParams.model ?? "unknown",
4131
4259
  event_type: "security_alert",
4132
4260
  severity: "warning",
4133
4261
  metadata: {
4134
4262
  ...params.guardParams.metadata ?? {},
4263
+ transformed_input: retainedInput,
4135
4264
  source: "guard",
4136
4265
  status: params.status,
4137
4266
  guard_reason: params.reason,
@@ -4203,98 +4332,122 @@ var AgentID = class {
4203
4332
  ...params,
4204
4333
  client_capabilities: params.client_capabilities ?? this.buildClientCapabilities()
4205
4334
  };
4206
- const guardCacheKey = this.buildGuardCacheKey(payload);
4335
+ const guardCacheKey = this.buildGuardCacheKey(payload, effectiveApiKey);
4207
4336
  const cachedVerdict = this.readCachedGuardVerdict(guardCacheKey);
4208
4337
  if (cachedVerdict) {
4209
4338
  return withGuardLatency(cachedVerdict);
4210
4339
  }
4211
- const correlationId = createCorrelationId(payload.client_event_id);
4212
- let lastStatusCode = null;
4213
- let lastAbort = false;
4214
- let lastError = null;
4215
- for (let attempt = 0; attempt < GUARD_MAX_ATTEMPTS; attempt += 1) {
4216
- const controller = new AbortController();
4217
- const timeoutId = setTimeout(() => controller.abort(), this.guardTimeoutMs);
4218
- try {
4219
- const res = await fetch(`${this.baseUrl}/guard`, {
4220
- method: "POST",
4221
- headers: {
4222
- "Content-Type": "application/json",
4223
- "x-agentid-api-key": effectiveApiKey,
4224
- "X-AgentID-SDK-Version": AGENTID_SDK_VERSION_HEADER,
4225
- "x-correlation-id": correlationId
4226
- },
4227
- body: JSON.stringify(payload),
4228
- signal: controller.signal
4229
- });
4230
- lastStatusCode = res.status;
4231
- const responseBody = await safeReadJson2(res);
4232
- if (responseBody && typeof responseBody.allowed === "boolean") {
4233
- const rawVerdict = responseBody;
4234
- const transparency = coerceTransparencyMetadata(rawVerdict.transparency);
4235
- const verdict = {
4236
- ...rawVerdict,
4237
- ...transparency ? { transparency } : {}
4238
- };
4239
- const infrastructureFailure = verdict.allowed === false && (isInfrastructureGuardReason(verdict.reason) || !verdict.reason && res.status >= 500);
4240
- if (infrastructureFailure) {
4241
- if (attempt < GUARD_MAX_ATTEMPTS - 1) {
4242
- await waitForRetry(attempt);
4243
- continue;
4244
- }
4245
- if (effectiveStrictMode) {
4340
+ const pendingGuardRequest = guardCacheKey ? this.pendingGuardRequests.get(guardCacheKey) : void 0;
4341
+ if (pendingGuardRequest) {
4342
+ return withGuardLatency(await pendingGuardRequest.promise);
4343
+ }
4344
+ const executeGuardRequest = async () => {
4345
+ const correlationId = createCorrelationId(payload.client_event_id);
4346
+ let lastStatusCode = null;
4347
+ let lastAbort = false;
4348
+ let lastError = null;
4349
+ for (let attempt = 0; attempt < GUARD_MAX_ATTEMPTS; attempt += 1) {
4350
+ const controller = new AbortController();
4351
+ const timeoutId = setTimeout(() => controller.abort(), this.guardTimeoutMs);
4352
+ try {
4353
+ const res = await fetch(`${this.baseUrl}/guard`, {
4354
+ method: "POST",
4355
+ headers: {
4356
+ "Content-Type": "application/json",
4357
+ "x-agentid-api-key": effectiveApiKey,
4358
+ "X-AgentID-SDK-Version": AGENTID_SDK_VERSION_HEADER,
4359
+ "x-correlation-id": correlationId
4360
+ },
4361
+ body: JSON.stringify(payload),
4362
+ signal: controller.signal
4363
+ });
4364
+ lastStatusCode = res.status;
4365
+ const responseBody = await safeReadJson2(res);
4366
+ if (responseBody && typeof responseBody.allowed === "boolean") {
4367
+ const rawVerdict = responseBody;
4368
+ const transparency = coerceTransparencyMetadata(rawVerdict.transparency);
4369
+ const verdict = {
4370
+ ...rawVerdict,
4371
+ ...transparency ? { transparency } : {}
4372
+ };
4373
+ const infrastructureFailure = verdict.allowed === false && (isInfrastructureGuardReason(verdict.reason) || !verdict.reason && res.status >= 500);
4374
+ if (infrastructureFailure) {
4375
+ if (attempt < GUARD_MAX_ATTEMPTS - 1) {
4376
+ await waitForRetry(attempt);
4377
+ continue;
4378
+ }
4379
+ if (effectiveStrictMode) {
4380
+ console.warn(
4381
+ `[AgentID] Guard API infrastructure failure in strict mode (${verdict.reason ?? `http_${res.status}`}). Blocking request.`
4382
+ );
4383
+ return withGuardLatency({
4384
+ allowed: false,
4385
+ reason: verdict.reason ?? "network_error_strict_mode"
4386
+ });
4387
+ }
4246
4388
  console.warn(
4247
- `[AgentID] Guard API infrastructure failure in strict mode (${verdict.reason ?? `http_${res.status}`}). Blocking request.`
4389
+ `[AgentID] Guard API infrastructure fallback in fail-open mode (${verdict.reason ?? `http_${res.status}`}).`
4248
4390
  );
4249
- return withGuardLatency({
4250
- allowed: false,
4251
- reason: verdict.reason ?? "network_error_strict_mode"
4391
+ this.logGuardFallback({
4392
+ reason: verdict.reason ?? `http_${res.status}`,
4393
+ status: "upstream_error",
4394
+ guardParams: params,
4395
+ apiKey: effectiveApiKey
4252
4396
  });
4397
+ return withGuardLatency(
4398
+ this.buildFailOpenGuardVerdict(
4399
+ "system_failure_fail_open",
4400
+ params.input,
4401
+ { apiKey: effectiveApiKey }
4402
+ )
4403
+ );
4253
4404
  }
4254
- console.warn(
4255
- `[AgentID] Guard API infrastructure fallback in fail-open mode (${verdict.reason ?? `http_${res.status}`}).`
4256
- );
4405
+ this.cacheGuardVerdict(guardCacheKey, verdict);
4406
+ return withGuardLatency(verdict);
4407
+ }
4408
+ if (!res.ok) {
4409
+ if (res.status >= 500 && attempt < GUARD_MAX_ATTEMPTS - 1) {
4410
+ await waitForRetry(attempt);
4411
+ continue;
4412
+ }
4413
+ throw new Error(`API Error ${res.status}`);
4414
+ }
4415
+ throw new Error("Invalid guard response");
4416
+ } catch (error) {
4417
+ lastError = error;
4418
+ const isAbortError2 = Boolean(
4419
+ error && typeof error === "object" && error.name === "AbortError"
4420
+ );
4421
+ lastAbort = isAbortError2;
4422
+ if (attempt < GUARD_MAX_ATTEMPTS - 1) {
4423
+ await waitForRetry(attempt);
4424
+ continue;
4425
+ }
4426
+ if (isAbortError2) {
4427
+ const timeoutMessage = "AgentID API Warning: Connection timeout exceeded.";
4428
+ console.warn(timeoutMessage);
4257
4429
  this.logGuardFallback({
4258
- reason: verdict.reason ?? `http_${res.status}`,
4259
- status: "upstream_error",
4430
+ reason: "timeout_fallback",
4431
+ status: "latency_timeout",
4260
4432
  guardParams: params,
4261
4433
  apiKey: effectiveApiKey
4262
4434
  });
4435
+ if (effectiveStrictMode) {
4436
+ return withGuardLatency({ allowed: false, reason: "network_error_strict_mode" });
4437
+ }
4263
4438
  return withGuardLatency(
4264
- this.buildFailOpenGuardVerdict(
4265
- "system_failure_fail_open",
4266
- params.input,
4267
- { apiKey: effectiveApiKey }
4268
- )
4439
+ this.buildFailOpenGuardVerdict("timeout_fallback", params.input, {
4440
+ apiKey: effectiveApiKey
4441
+ })
4269
4442
  );
4270
4443
  }
4271
- this.cacheGuardVerdict(guardCacheKey, verdict);
4272
- return withGuardLatency(verdict);
4273
- }
4274
- if (!res.ok) {
4275
- if (res.status >= 500 && attempt < GUARD_MAX_ATTEMPTS - 1) {
4276
- await waitForRetry(attempt);
4277
- continue;
4278
- }
4279
- throw new Error(`API Error ${res.status}`);
4280
- }
4281
- throw new Error("Invalid guard response");
4282
- } catch (error) {
4283
- lastError = error;
4284
- const isAbortError2 = Boolean(
4285
- error && typeof error === "object" && error.name === "AbortError"
4286
- );
4287
- lastAbort = isAbortError2;
4288
- if (attempt < GUARD_MAX_ATTEMPTS - 1) {
4289
- await waitForRetry(attempt);
4290
- continue;
4291
- }
4292
- if (isAbortError2) {
4293
- const timeoutMessage = "AgentID API Warning: Connection timeout exceeded.";
4294
- console.warn(timeoutMessage);
4444
+ console.warn(
4445
+ effectiveStrictMode ? "[AgentID] Guard check failed (Strict mode active):" : "[AgentID] Guard check failed (Fail-Open active):",
4446
+ error
4447
+ );
4295
4448
  this.logGuardFallback({
4296
- reason: "timeout_fallback",
4297
- status: "latency_timeout",
4449
+ reason: "guard_unreachable",
4450
+ status: "guard_unreachable",
4298
4451
  guardParams: params,
4299
4452
  apiKey: effectiveApiKey
4300
4453
  });
@@ -4302,67 +4455,62 @@ var AgentID = class {
4302
4455
  return withGuardLatency({ allowed: false, reason: "network_error_strict_mode" });
4303
4456
  }
4304
4457
  return withGuardLatency(
4305
- this.buildFailOpenGuardVerdict("timeout_fallback", params.input, {
4458
+ this.buildFailOpenGuardVerdict("guard_unreachable", params.input, {
4306
4459
  apiKey: effectiveApiKey
4307
4460
  })
4308
4461
  );
4462
+ } finally {
4463
+ clearTimeout(timeoutId);
4309
4464
  }
4310
- console.warn(
4311
- effectiveStrictMode ? "[AgentID] Guard check failed (Strict mode active):" : "[AgentID] Guard check failed (Fail-Open active):",
4312
- error
4313
- );
4314
- this.logGuardFallback({
4315
- reason: "guard_unreachable",
4316
- status: "guard_unreachable",
4317
- guardParams: params,
4318
- apiKey: effectiveApiKey
4319
- });
4465
+ }
4466
+ if (lastAbort) {
4320
4467
  if (effectiveStrictMode) {
4321
4468
  return withGuardLatency({ allowed: false, reason: "network_error_strict_mode" });
4322
4469
  }
4323
4470
  return withGuardLatency(
4324
- this.buildFailOpenGuardVerdict("guard_unreachable", params.input, {
4471
+ this.buildFailOpenGuardVerdict("timeout_fallback", params.input, {
4325
4472
  apiKey: effectiveApiKey
4326
4473
  })
4327
4474
  );
4328
- } finally {
4329
- clearTimeout(timeoutId);
4330
4475
  }
4331
- }
4332
- if (lastAbort) {
4476
+ if (typeof lastStatusCode === "number" && lastStatusCode >= 500) {
4477
+ if (effectiveStrictMode) {
4478
+ return withGuardLatency({ allowed: false, reason: "server_error" });
4479
+ }
4480
+ return withGuardLatency(
4481
+ this.buildFailOpenGuardVerdict(
4482
+ "system_failure_fail_open",
4483
+ params.input,
4484
+ { apiKey: effectiveApiKey }
4485
+ )
4486
+ );
4487
+ }
4488
+ console.warn(
4489
+ effectiveStrictMode ? "[AgentID] Guard check failed (Strict mode active):" : "[AgentID] Guard check failed (Fail-Open active):",
4490
+ lastError
4491
+ );
4333
4492
  if (effectiveStrictMode) {
4334
4493
  return withGuardLatency({ allowed: false, reason: "network_error_strict_mode" });
4335
4494
  }
4336
4495
  return withGuardLatency(
4337
- this.buildFailOpenGuardVerdict("timeout_fallback", params.input, {
4496
+ this.buildFailOpenGuardVerdict("guard_unreachable", params.input, {
4338
4497
  apiKey: effectiveApiKey
4339
4498
  })
4340
4499
  );
4500
+ };
4501
+ if (!guardCacheKey) {
4502
+ return executeGuardRequest();
4341
4503
  }
4342
- if (typeof lastStatusCode === "number" && lastStatusCode >= 500) {
4343
- if (effectiveStrictMode) {
4344
- return withGuardLatency({ allowed: false, reason: "server_error" });
4504
+ const promise = executeGuardRequest();
4505
+ this.pendingGuardRequests.set(guardCacheKey, { promise });
4506
+ try {
4507
+ return await promise;
4508
+ } finally {
4509
+ const pending = this.pendingGuardRequests.get(guardCacheKey);
4510
+ if (pending?.promise === promise) {
4511
+ this.pendingGuardRequests.delete(guardCacheKey);
4345
4512
  }
4346
- return withGuardLatency(
4347
- this.buildFailOpenGuardVerdict(
4348
- "system_failure_fail_open",
4349
- params.input,
4350
- { apiKey: effectiveApiKey }
4351
- )
4352
- );
4353
- }
4354
- console.warn(
4355
- effectiveStrictMode ? "[AgentID] Guard check failed (Strict mode active):" : "[AgentID] Guard check failed (Fail-Open active):",
4356
- lastError
4357
- );
4358
- if (effectiveStrictMode) {
4359
- return withGuardLatency({ allowed: false, reason: "network_error_strict_mode" });
4360
4513
  }
4361
- return withGuardLatency(
4362
- this.buildFailOpenGuardVerdict("guard_unreachable", params.input, {
4363
- apiKey: effectiveApiKey
4364
- })
4365
- );
4366
4514
  }
4367
4515
  async sendIngest(params, options, internal) {
4368
4516
  const ingestStartedAt = Date.now();
@@ -4606,11 +4754,12 @@ var AgentID = class {
4606
4754
  completion,
4607
4755
  options?.piiMapping
4608
4756
  );
4757
+ const transformedOutput = options?.deanonymizeForClient === true && options.piiMapping ? this.pii.deanonymize(completion, options.piiMapping) : masked.maskedText;
4609
4758
  return {
4610
4759
  mode: "static",
4611
4760
  rawOutput: completion,
4612
- transformedOutput: masked.maskedText,
4613
- outputMasked: masked.maskedText !== completion || placeholderOutputMasked
4761
+ transformedOutput,
4762
+ outputMasked: transformedOutput !== completion || placeholderOutputMasked
4614
4763
  };
4615
4764
  }
4616
4765
  if (!isAsyncIterable(completion)) {
@@ -4620,11 +4769,12 @@ var AgentID = class {
4620
4769
  asText,
4621
4770
  options?.piiMapping
4622
4771
  );
4772
+ const transformedOutput = options?.deanonymizeForClient === true && options.piiMapping ? this.pii.deanonymize(asText, options.piiMapping) : masked.maskedText;
4623
4773
  return {
4624
4774
  mode: "static",
4625
4775
  rawOutput: asText,
4626
- transformedOutput: masked.maskedText,
4627
- outputMasked: masked.maskedText !== asText || placeholderOutputMasked
4776
+ transformedOutput,
4777
+ outputMasked: transformedOutput !== asText || placeholderOutputMasked
4628
4778
  };
4629
4779
  }
4630
4780
  const source = completion;
@@ -4819,6 +4969,7 @@ var AgentID = class {
4819
4969
  */
4820
4970
  wrapOpenAI(openai, options) {
4821
4971
  const systemId = options.system_id;
4972
+ const deanonymizeOutputForClient = options.deanonymizeOutputForClient === true || options.deanonymize_output_for_client === true;
4822
4973
  const expectedLanguages = normalizeExpectedLanguages(
4823
4974
  options.expected_languages ?? options.expectedLanguages
4824
4975
  );
@@ -4859,38 +5010,48 @@ var AgentID = class {
4859
5010
  const stream = adapter.isStream(providerReq);
4860
5011
  let capabilityConfig = this.getCachedCapabilityConfig(requestOptions);
4861
5012
  const userText = adapter.extractInput(providerReq);
4862
- const requestAttachments = adapter.extractAttachments(providerReq);
5013
+ const rawPromptContext = adapter.extractPromptContext(providerReq);
5014
+ let requestAttachments = adapter.extractAttachments(providerReq);
4863
5015
  const hasGuardContent = userText !== null || requestAttachments.length > 0;
4864
5016
  let maskedText = userText ?? "";
4865
5017
  let maskedReq = providerReq;
4866
5018
  let createArgs = providerReq === rawReq ? normalizedCreateArgs : [{ ...providerReq }, ...normalizedCreateArgs.slice(1)];
4867
5019
  let mapping = {};
5020
+ let clientInputMaskingTelemetry = {
5021
+ piiApplied: false,
5022
+ secretApplied: false
5023
+ };
4868
5024
  let sdkConfigFetchMs = 0;
4869
5025
  let sdkLocalScanMs = 0;
4870
- let providerMaskingOptions;
4871
5026
  if (hasGuardContent) {
4872
5027
  const prepared = await this.prepareInputForDispatch({
4873
5028
  input: userText ?? "",
5029
+ promptContext: rawPromptContext ?? void 0,
4874
5030
  systemId,
4875
5031
  stream,
4876
5032
  clientEventId,
4877
5033
  telemetryMetadata
4878
5034
  }, requestOptions);
4879
5035
  capabilityConfig = prepared.capabilityConfig;
4880
- providerMaskingOptions = {
4881
- pii: !capabilityConfig.block_pii_leakage && this.resolveEffectivePiiMasking(capabilityConfig),
4882
- secrets: !capabilityConfig.block_secret_leakage && this.resolveEffectiveSecretMasking(capabilityConfig)
4883
- };
4884
5036
  maskedText = prepared.sanitizedInput;
4885
- 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 ?? {};
4886
5046
  sdkConfigFetchMs = prepared.sdkConfigFetchMs ?? 0;
4887
5047
  sdkLocalScanMs = prepared.sdkLocalScanMs ?? 0;
4888
- if (maskedText !== (userText ?? "")) {
5048
+ const shouldProtectRequestHistory = maskedText !== (userText ?? "");
5049
+ if (shouldProtectRequestHistory) {
4889
5050
  maskedReq = this.withMaskedOpenAIRequest(
4890
5051
  providerReq,
4891
- maskedText,
4892
- providerMaskingOptions
5052
+ maskedText
4893
5053
  );
5054
+ requestAttachments = adapter.extractAttachments(maskedReq);
4894
5055
  const nextCreateArgs = [...createArgs];
4895
5056
  nextCreateArgs[0] = maskedReq;
4896
5057
  createArgs = nextCreateArgs;
@@ -4901,8 +5062,16 @@ var AgentID = class {
4901
5062
  "AgentID: No user message or supported inline attachment found. Security guard requires prompt content."
4902
5063
  );
4903
5064
  }
5065
+ const promptContextForGuard = adapter.extractPromptContext(maskedReq) ?? rawPromptContext ?? void 0;
5066
+ const clientCapabilities = this.buildClientCapabilities(
5067
+ "openai",
5068
+ false,
5069
+ capabilityConfig,
5070
+ clientInputMaskingTelemetry
5071
+ );
4904
5072
  const verdict = await this.guard({
4905
5073
  input: maskedText,
5074
+ prompt_context: promptContextForGuard,
4906
5075
  system_id: systemId,
4907
5076
  model: adapter.getModelName(maskedReq),
4908
5077
  user_id: options.user_id,
@@ -4911,63 +5080,54 @@ var AgentID = class {
4911
5080
  request_identity: options.request_identity,
4912
5081
  metadata: telemetryMetadata,
4913
5082
  attachments: requestAttachments,
4914
- client_capabilities: this.buildClientCapabilities(
4915
- "openai",
4916
- false,
4917
- capabilityConfig
4918
- )
5083
+ client_capabilities: clientCapabilities
4919
5084
  }, requestOptions);
4920
5085
  let localFallbackApplied = false;
4921
5086
  let localFallbackReason = null;
4922
5087
  if (!verdict.allowed) {
4923
- if (effectiveStrictMode && isGuardFailureEligibleForLocalFallback(verdict.reason)) {
4924
- localFallbackApplied = true;
4925
- localFallbackReason = verdict.reason ?? "guard_unreachable";
4926
- if (sdkLocalScanMs === 0) {
4927
- const fallback = await this.applyLocalPolicyChecks({
4928
- input: maskedText,
4929
- systemId,
4930
- stream,
4931
- capabilityConfig,
4932
- apiKey: effectiveApiKey,
4933
- clientEventId,
4934
- sdkConfigFetchMs,
4935
- telemetryMetadata,
4936
- runPromptInjectionCheck: true
4937
- });
4938
- maskedText = fallback.sanitizedInput;
4939
- sdkLocalScanMs = fallback.sdkLocalScanMs;
4940
- }
4941
- } else {
4942
- await this.logPromptPreflightStep(
4943
- {
4944
- system_id: systemId,
4945
- user_id: options.user_id,
4946
- request_identity: options.request_identity,
4947
- input: maskedText,
4948
- telemetry: telemetryMetadata,
4949
- verdict,
4950
- guard_event_id: verdict.guard_event_id ?? null,
4951
- 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),
4952
- preflight_for_client_event_id: typeof verdict.client_event_id === "string" && isUuidLike2(verdict.client_event_id) ? verdict.client_event_id : clientEventId,
4953
- client_capabilities: this.buildClientCapabilities(
4954
- "openai",
4955
- false,
4956
- capabilityConfig
4957
- ),
4958
- runtime_surface: "openai_sdk_guard"
4959
- },
4960
- requestOptions
4961
- );
4962
- throw new SecurityBlockError(verdict.reason ?? "guard_denied");
4963
- }
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;
4964
5125
  }
4965
5126
  const currentRequestInput = adapter.extractInput(maskedReq) ?? "";
4966
- if (maskedText !== currentRequestInput || providerMaskingOptions?.pii === true || providerMaskingOptions?.secrets === true) {
5127
+ if (maskedText !== currentRequestInput) {
4967
5128
  maskedReq = this.withMaskedOpenAIRequest(
4968
5129
  providerReq,
4969
- maskedText,
4970
- providerMaskingOptions
5130
+ maskedText
4971
5131
  );
4972
5132
  const nextCreateArgs = [...createArgs];
4973
5133
  nextCreateArgs[0] = maskedReq;
@@ -4990,29 +5150,29 @@ var AgentID = class {
4990
5150
  maskedText = transformedInput;
4991
5151
  maskedReq = this.withMaskedOpenAIRequest(
4992
5152
  providerReq,
4993
- transformedInput,
4994
- providerMaskingOptions
5153
+ transformedInput
4995
5154
  );
4996
5155
  const nextCreateArgs = [...createArgs];
4997
5156
  nextCreateArgs[0] = maskedReq;
4998
5157
  createArgs = nextCreateArgs;
4999
5158
  }
5159
+ const shouldDeanonymizeForClient = deanonymizeOutputForClient && !isShadowMode && Object.keys(mapping).length > 0;
5160
+ const retainedInputForLogs = getZeroRetentionInput(
5161
+ userText ?? "",
5162
+ maskedText
5163
+ );
5000
5164
  await this.logPromptPreflightStep(
5001
5165
  {
5002
5166
  system_id: systemId,
5003
5167
  user_id: options.user_id,
5004
5168
  request_identity: options.request_identity,
5005
- input: maskedText,
5169
+ input: retainedInputForLogs,
5006
5170
  telemetry: telemetryMetadata,
5007
5171
  verdict,
5008
5172
  guard_event_id: guardEventId,
5009
5173
  guard_latency_ms: guardLatencyMs,
5010
5174
  preflight_for_client_event_id: canonicalClientEventId,
5011
- client_capabilities: this.buildClientCapabilities(
5012
- "openai",
5013
- false,
5014
- capabilityConfig
5015
- ),
5175
+ client_capabilities: clientCapabilities,
5016
5176
  local_fallback_applied: localFallbackApplied,
5017
5177
  local_fallback_reason: localFallbackReason,
5018
5178
  runtime_surface: "openai_sdk_guard"
@@ -5030,12 +5190,13 @@ var AgentID = class {
5030
5190
  })(),
5031
5191
  {
5032
5192
  piiMapping: mapping,
5033
- deanonymizeForClient: false,
5034
- maskForClient: !isShadowMode
5193
+ deanonymizeForClient: shouldDeanonymizeForClient,
5194
+ maskForClient: !isShadowMode && !shouldDeanonymizeForClient
5035
5195
  }
5036
5196
  );
5037
5197
  if (maskedText && wrappedCompletion.mode === "stream") {
5038
5198
  void wrappedCompletion.done.then(async (result) => {
5199
+ const effectiveInputMaskingTelemetry = getMaskingTelemetryFromMapping(mapping);
5039
5200
  const modelLatencyMs2 = Math.max(0, Date.now() - modelStartedAt2);
5040
5201
  const totalPipelineLatencyMs2 = Math.max(0, Date.now() - pipelineStartedAt);
5041
5202
  const outputForLog = result.transformedOutput;
@@ -5044,7 +5205,7 @@ var AgentID = class {
5044
5205
  system_id: systemId,
5045
5206
  user_id: options.user_id,
5046
5207
  request_identity: options.request_identity,
5047
- input: maskedText,
5208
+ input: retainedInputForLogs,
5048
5209
  output: outputForLog,
5049
5210
  model: adapter.getModelName(maskedReq),
5050
5211
  usage: result.usage,
@@ -5053,9 +5214,17 @@ var AgentID = class {
5053
5214
  metadata: mergeTelemetryContexts(
5054
5215
  telemetryMetadata,
5055
5216
  {
5056
- transformed_input: maskedText,
5217
+ transformed_input: retainedInputForLogs,
5057
5218
  transformed_output: result.transformedOutput,
5058
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,
5059
5228
  shadow_mode: isShadowMode,
5060
5229
  simulated_decision: verdict.simulated_decision ?? null,
5061
5230
  simulated_output_decision: isShadowMode && result.outputMasked ? "masked" : "allowed",
@@ -5076,11 +5245,7 @@ var AgentID = class {
5076
5245
  sdkConfigVersion: capabilityConfig.version
5077
5246
  })
5078
5247
  ),
5079
- client_capabilities: this.buildClientCapabilities(
5080
- "openai",
5081
- false,
5082
- capabilityConfig
5083
- )
5248
+ client_capabilities: clientCapabilities
5084
5249
  }, requestOptions);
5085
5250
  if (!ingestResult.ok) {
5086
5251
  this.maybeRaiseStrictIngestDependencyError({
@@ -5105,6 +5270,7 @@ var AgentID = class {
5105
5270
  const modelLatencyMs = Math.max(0, Date.now() - modelStartedAt);
5106
5271
  const totalPipelineLatencyMs = Math.max(0, Date.now() - pipelineStartedAt);
5107
5272
  if (maskedText) {
5273
+ const effectiveInputMaskingTelemetry = getMaskingTelemetryFromMapping(mapping);
5108
5274
  const output = adapter.extractOutput(res);
5109
5275
  const wrappedCompletion = this.wrapCompletion(output, {
5110
5276
  piiMapping: mapping,
@@ -5118,7 +5284,7 @@ var AgentID = class {
5118
5284
  system_id: systemId,
5119
5285
  user_id: options.user_id,
5120
5286
  request_identity: options.request_identity,
5121
- input: maskedText,
5287
+ input: retainedInputForLogs,
5122
5288
  output: outputForLog,
5123
5289
  model,
5124
5290
  usage,
@@ -5127,9 +5293,17 @@ var AgentID = class {
5127
5293
  metadata: mergeTelemetryContexts(
5128
5294
  telemetryMetadata,
5129
5295
  {
5130
- transformed_input: maskedText,
5296
+ transformed_input: retainedInputForLogs,
5131
5297
  transformed_output: wrappedCompletion.transformedOutput,
5132
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,
5133
5307
  shadow_mode: isShadowMode,
5134
5308
  simulated_decision: verdict.simulated_decision ?? null,
5135
5309
  simulated_output_decision: isShadowMode && wrappedCompletion.outputMasked ? "masked" : "allowed",
@@ -5150,11 +5324,7 @@ var AgentID = class {
5150
5324
  sdkConfigVersion: capabilityConfig.version
5151
5325
  })
5152
5326
  ),
5153
- client_capabilities: this.buildClientCapabilities(
5154
- "openai",
5155
- false,
5156
- capabilityConfig
5157
- )
5327
+ client_capabilities: clientCapabilities
5158
5328
  }, requestOptions);
5159
5329
  if (!ingestResult.ok) {
5160
5330
  this.maybeRaiseStrictIngestDependencyError({
@@ -5168,7 +5338,7 @@ var AgentID = class {
5168
5338
  }
5169
5339
  if (!isShadowMode && maskedText) {
5170
5340
  const output = adapter.extractOutput(res);
5171
- const maskedOutput = this.wrapCompletion(output, {
5341
+ const clientFacingOutput = shouldDeanonymizeForClient ? this.pii.deanonymize(String(output ?? ""), mapping) : this.wrapCompletion(output, {
5172
5342
  piiMapping: mapping,
5173
5343
  deanonymizeForClient: false
5174
5344
  }).transformedOutput;
@@ -5177,10 +5347,10 @@ var AgentID = class {
5177
5347
  for (const choice of res.choices) {
5178
5348
  const typedChoice = choice;
5179
5349
  if (typedChoice?.message && typeof typedChoice.message.content === "string") {
5180
- typedChoice.message.content = maskedOutput;
5350
+ typedChoice.message.content = clientFacingOutput;
5181
5351
  }
5182
5352
  if (typedChoice?.delta && typeof typedChoice.delta.content === "string") {
5183
- typedChoice.delta.content = maskedOutput;
5353
+ typedChoice.delta.content = clientFacingOutput;
5184
5354
  }
5185
5355
  }
5186
5356
  }
@@ -5365,13 +5535,15 @@ function protectMessageHistory(messages, options = { pii: true, secrets: true })
5365
5535
  const piiManager = new PIIManager();
5366
5536
  let textPartsCount = 0;
5367
5537
  let transformedTextPartsCount = 0;
5538
+ const placeholderMapping = {};
5368
5539
  const protectString = (value) => {
5369
5540
  textPartsCount += 1;
5370
- const masked = piiManager.anonymize(value, options).maskedText;
5371
- if (masked !== value) {
5541
+ const masked = piiManager.anonymize(value, options);
5542
+ Object.assign(placeholderMapping, masked.mapping);
5543
+ if (masked.maskedText !== value) {
5372
5544
  transformedTextPartsCount += 1;
5373
5545
  }
5374
- return masked;
5546
+ return masked.maskedText;
5375
5547
  };
5376
5548
  const visit = (value, key) => {
5377
5549
  if (typeof value === "string") {
@@ -5403,7 +5575,31 @@ function protectMessageHistory(messages, options = { pii: true, secrets: true })
5403
5575
  messages: protectedMessages,
5404
5576
  transformed: protectedMessages !== messages,
5405
5577
  textPartsCount,
5406
- 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
5407
5603
  };
5408
5604
  }
5409
5605
  // Annotate the CommonJS export names for ESM import in node:
@@ -5421,6 +5617,7 @@ function protectMessageHistory(messages, options = { pii: true, secrets: true })
5421
5617
  createAgentIdTelemetryContext,
5422
5618
  createAgentIdWorkflowTrail,
5423
5619
  getInjectionScanner,
5620
+ protectChatState,
5424
5621
  protectMessageHistory,
5425
5622
  scanWithRegex
5426
5623
  });