langchain 1.0.4 → 1.0.6

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.
Files changed (108) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/agents/ReactAgent.cjs +56 -54
  3. package/dist/agents/ReactAgent.cjs.map +1 -1
  4. package/dist/agents/ReactAgent.d.cts +3 -3
  5. package/dist/agents/ReactAgent.d.cts.map +1 -1
  6. package/dist/agents/ReactAgent.d.ts +3 -3
  7. package/dist/agents/ReactAgent.d.ts.map +1 -1
  8. package/dist/agents/ReactAgent.js +58 -56
  9. package/dist/agents/ReactAgent.js.map +1 -1
  10. package/dist/agents/middleware/contextEditing.cjs +302 -33
  11. package/dist/agents/middleware/contextEditing.cjs.map +1 -1
  12. package/dist/agents/middleware/contextEditing.d.cts +125 -41
  13. package/dist/agents/middleware/contextEditing.d.cts.map +1 -1
  14. package/dist/agents/middleware/contextEditing.d.ts +125 -41
  15. package/dist/agents/middleware/contextEditing.d.ts.map +1 -1
  16. package/dist/agents/middleware/contextEditing.js +302 -33
  17. package/dist/agents/middleware/contextEditing.js.map +1 -1
  18. package/dist/agents/middleware/dynamicSystemPrompt.d.cts.map +1 -1
  19. package/dist/agents/middleware/dynamicSystemPrompt.d.ts.map +1 -1
  20. package/dist/agents/middleware/hitl.d.cts.map +1 -1
  21. package/dist/agents/middleware/hitl.d.ts.map +1 -1
  22. package/dist/agents/middleware/index.cjs +2 -0
  23. package/dist/agents/middleware/index.js +2 -0
  24. package/dist/agents/middleware/llmToolSelector.d.cts +4 -4
  25. package/dist/agents/middleware/llmToolSelector.d.cts.map +1 -1
  26. package/dist/agents/middleware/modelCallLimit.cjs +6 -2
  27. package/dist/agents/middleware/modelCallLimit.cjs.map +1 -1
  28. package/dist/agents/middleware/modelCallLimit.d.cts +8 -8
  29. package/dist/agents/middleware/modelCallLimit.d.cts.map +1 -1
  30. package/dist/agents/middleware/modelCallLimit.d.ts +8 -8
  31. package/dist/agents/middleware/modelCallLimit.d.ts.map +1 -1
  32. package/dist/agents/middleware/modelCallLimit.js +6 -2
  33. package/dist/agents/middleware/modelCallLimit.js.map +1 -1
  34. package/dist/agents/middleware/modelFallback.cjs +2 -2
  35. package/dist/agents/middleware/modelFallback.cjs.map +1 -1
  36. package/dist/agents/middleware/modelFallback.d.cts +2 -2
  37. package/dist/agents/middleware/modelFallback.d.cts.map +1 -1
  38. package/dist/agents/middleware/modelFallback.d.ts +2 -2
  39. package/dist/agents/middleware/modelFallback.d.ts.map +1 -1
  40. package/dist/agents/middleware/modelFallback.js +2 -2
  41. package/dist/agents/middleware/modelFallback.js.map +1 -1
  42. package/dist/agents/middleware/pii.cjs +445 -0
  43. package/dist/agents/middleware/pii.cjs.map +1 -0
  44. package/dist/agents/middleware/pii.d.cts +216 -0
  45. package/dist/agents/middleware/pii.d.cts.map +1 -0
  46. package/dist/agents/middleware/pii.d.ts +216 -0
  47. package/dist/agents/middleware/pii.d.ts.map +1 -0
  48. package/dist/agents/middleware/pii.js +436 -0
  49. package/dist/agents/middleware/pii.js.map +1 -0
  50. package/dist/agents/middleware/piiRedaction.cjs +2 -1
  51. package/dist/agents/middleware/piiRedaction.cjs.map +1 -1
  52. package/dist/agents/middleware/piiRedaction.d.cts +4 -1
  53. package/dist/agents/middleware/piiRedaction.d.cts.map +1 -1
  54. package/dist/agents/middleware/piiRedaction.d.ts +4 -1
  55. package/dist/agents/middleware/piiRedaction.d.ts.map +1 -1
  56. package/dist/agents/middleware/piiRedaction.js +2 -1
  57. package/dist/agents/middleware/piiRedaction.js.map +1 -1
  58. package/dist/agents/middleware/promptCaching.d.cts.map +1 -1
  59. package/dist/agents/middleware/promptCaching.d.ts.map +1 -1
  60. package/dist/agents/middleware/summarization.cjs +15 -24
  61. package/dist/agents/middleware/summarization.cjs.map +1 -1
  62. package/dist/agents/middleware/summarization.d.cts +72 -9
  63. package/dist/agents/middleware/summarization.d.cts.map +1 -1
  64. package/dist/agents/middleware/summarization.d.ts +65 -2
  65. package/dist/agents/middleware/summarization.d.ts.map +1 -1
  66. package/dist/agents/middleware/summarization.js +13 -25
  67. package/dist/agents/middleware/summarization.js.map +1 -1
  68. package/dist/agents/middleware/todoListMiddleware.d.cts.map +1 -1
  69. package/dist/agents/middleware/todoListMiddleware.d.ts.map +1 -1
  70. package/dist/agents/middleware/toolCallLimit.d.cts.map +1 -1
  71. package/dist/agents/middleware/toolCallLimit.d.ts.map +1 -1
  72. package/dist/agents/middleware/toolEmulator.cjs +118 -0
  73. package/dist/agents/middleware/toolEmulator.cjs.map +1 -0
  74. package/dist/agents/middleware/toolEmulator.d.cts +76 -0
  75. package/dist/agents/middleware/toolEmulator.d.cts.map +1 -0
  76. package/dist/agents/middleware/toolEmulator.d.ts +76 -0
  77. package/dist/agents/middleware/toolEmulator.d.ts.map +1 -0
  78. package/dist/agents/middleware/toolEmulator.js +117 -0
  79. package/dist/agents/middleware/toolEmulator.js.map +1 -0
  80. package/dist/agents/middleware/utils.cjs +4 -0
  81. package/dist/agents/middleware/utils.cjs.map +1 -1
  82. package/dist/agents/middleware/utils.d.cts.map +1 -1
  83. package/dist/agents/middleware/utils.d.ts.map +1 -1
  84. package/dist/agents/middleware/utils.js +4 -0
  85. package/dist/agents/middleware/utils.js.map +1 -1
  86. package/dist/agents/nodes/AgentNode.cjs +23 -7
  87. package/dist/agents/nodes/AgentNode.cjs.map +1 -1
  88. package/dist/agents/nodes/AgentNode.js +23 -8
  89. package/dist/agents/nodes/AgentNode.js.map +1 -1
  90. package/dist/agents/nodes/ToolNode.cjs +5 -0
  91. package/dist/agents/nodes/ToolNode.cjs.map +1 -1
  92. package/dist/agents/nodes/ToolNode.js +5 -1
  93. package/dist/agents/nodes/ToolNode.js.map +1 -1
  94. package/dist/agents/responses.cjs.map +1 -1
  95. package/dist/agents/responses.d.cts +2 -0
  96. package/dist/agents/responses.d.cts.map +1 -1
  97. package/dist/agents/responses.d.ts +2 -0
  98. package/dist/agents/responses.d.ts.map +1 -1
  99. package/dist/agents/responses.js.map +1 -1
  100. package/dist/agents/runtime.d.cts +5 -5
  101. package/dist/agents/runtime.d.cts.map +1 -1
  102. package/dist/agents/runtime.d.ts +5 -5
  103. package/dist/agents/runtime.d.ts.map +1 -1
  104. package/dist/index.cjs +22 -0
  105. package/dist/index.d.cts +5 -3
  106. package/dist/index.d.ts +5 -3
  107. package/dist/index.js +13 -1
  108. package/package.json +9 -8
@@ -0,0 +1,445 @@
1
+ const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
+ const require_middleware = require('../middleware.cjs');
3
+ const __langchain_core_messages = require_rolldown_runtime.__toESM(require("@langchain/core/messages"));
4
+ const zod_v3 = require_rolldown_runtime.__toESM(require("zod/v3"));
5
+ const __langchain_core_utils_hash = require_rolldown_runtime.__toESM(require("@langchain/core/utils/hash"));
6
+
7
+ //#region src/agents/middleware/pii.ts
8
+ /**
9
+ * Error thrown when PII is detected and strategy is 'block'
10
+ */
11
+ var PIIDetectionError = class extends Error {
12
+ constructor(piiType, matches) {
13
+ super(`PII detected: ${piiType} found ${matches.length} occurrence(s)`);
14
+ this.piiType = piiType;
15
+ this.matches = matches;
16
+ this.name = "PIIDetectionError";
17
+ }
18
+ };
19
+ /**
20
+ * Email detection regex pattern
21
+ */
22
+ const EMAIL_PATTERN = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g;
23
+ /**
24
+ * Credit card detection regex pattern (basic, will be validated with Luhn)
25
+ */
26
+ const CREDIT_CARD_PATTERN = /\b(?:\d{4}[-\s]?){3}\d{4}\b/g;
27
+ /**
28
+ * IP address detection regex pattern
29
+ */
30
+ const IP_PATTERN = /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/g;
31
+ /**
32
+ * MAC address detection regex pattern
33
+ */
34
+ const MAC_ADDRESS_PATTERN = /\b(?:[0-9A-Fa-f]{2}[:-]){5}(?:[0-9A-Fa-f]{2})\b/g;
35
+ /**
36
+ * URL detection regex pattern
37
+ */
38
+ const URL_PATTERN = /(?:https?:\/\/|www\.)[^\s<>"{}|\\^`[\]]+/gi;
39
+ /**
40
+ * Luhn algorithm for credit card validation
41
+ */
42
+ function luhnCheck(cardNumber) {
43
+ const digits = cardNumber.replace(/\D/g, "");
44
+ let sum = 0;
45
+ let isEven = false;
46
+ for (let i = digits.length - 1; i >= 0; i--) {
47
+ let digit = parseInt(digits[i], 10);
48
+ if (isEven) {
49
+ digit *= 2;
50
+ if (digit > 9) digit -= 9;
51
+ }
52
+ sum += digit;
53
+ isEven = !isEven;
54
+ }
55
+ return sum % 10 === 0;
56
+ }
57
+ /**
58
+ * Convert regex match to PIIMatch
59
+ */
60
+ function regexMatchToPIIMatch(match) {
61
+ return {
62
+ text: match[0],
63
+ start: match.index ?? 0,
64
+ end: (match.index ?? 0) + match[0].length
65
+ };
66
+ }
67
+ /**
68
+ * Detect email addresses in content
69
+ */
70
+ function detectEmail(content) {
71
+ const matches = [];
72
+ const regex = new RegExp(EMAIL_PATTERN);
73
+ let match;
74
+ while ((match = regex.exec(content)) !== null) matches.push(regexMatchToPIIMatch(match));
75
+ return matches;
76
+ }
77
+ /**
78
+ * Detect credit card numbers in content (validated with Luhn algorithm)
79
+ */
80
+ function detectCreditCard(content) {
81
+ const matches = [];
82
+ const regex = new RegExp(CREDIT_CARD_PATTERN);
83
+ let match;
84
+ while ((match = regex.exec(content)) !== null) {
85
+ const cardNumber = match[0].replace(/\D/g, "");
86
+ if (cardNumber.length >= 13 && cardNumber.length <= 19 && luhnCheck(cardNumber)) matches.push(regexMatchToPIIMatch(match));
87
+ }
88
+ return matches;
89
+ }
90
+ /**
91
+ * Detect IP addresses in content (validated)
92
+ */
93
+ function detectIP(content) {
94
+ const matches = [];
95
+ const regex = new RegExp(IP_PATTERN);
96
+ let match;
97
+ while ((match = regex.exec(content)) !== null) {
98
+ const ip = match[0];
99
+ const parts = ip.split(".");
100
+ if (parts.length === 4 && parts.every((part) => {
101
+ const num = parseInt(part, 10);
102
+ return num >= 0 && num <= 255;
103
+ })) matches.push(regexMatchToPIIMatch(match));
104
+ }
105
+ return matches;
106
+ }
107
+ /**
108
+ * Detect MAC addresses in content
109
+ */
110
+ function detectMacAddress(content) {
111
+ const matches = [];
112
+ const regex = new RegExp(MAC_ADDRESS_PATTERN);
113
+ let match;
114
+ while ((match = regex.exec(content)) !== null) matches.push(regexMatchToPIIMatch(match));
115
+ return matches;
116
+ }
117
+ /**
118
+ * Detect URLs in content
119
+ */
120
+ function detectUrl(content) {
121
+ const matches = [];
122
+ const regex = new RegExp(URL_PATTERN);
123
+ let match;
124
+ while ((match = regex.exec(content)) !== null) matches.push(regexMatchToPIIMatch(match));
125
+ return matches;
126
+ }
127
+ /**
128
+ * Built-in detector map
129
+ */
130
+ const BUILT_IN_DETECTORS = {
131
+ email: detectEmail,
132
+ credit_card: detectCreditCard,
133
+ ip: detectIP,
134
+ mac_address: detectMacAddress,
135
+ url: detectUrl
136
+ };
137
+ /**
138
+ * Resolve a redaction rule to a concrete detector function
139
+ */
140
+ function resolveRedactionRule(config) {
141
+ let detector;
142
+ if (config.detector) if (typeof config.detector === "string") {
143
+ const regex = new RegExp(config.detector, "g");
144
+ detector = (content) => {
145
+ const matches = [];
146
+ let match;
147
+ const regexCopy = new RegExp(regex);
148
+ while ((match = regexCopy.exec(content)) !== null) matches.push(regexMatchToPIIMatch(match));
149
+ return matches;
150
+ };
151
+ } else if (config.detector instanceof RegExp) detector = (content) => {
152
+ if (!(config.detector instanceof RegExp)) throw new Error("Detector is required");
153
+ const matches = [];
154
+ let match;
155
+ while ((match = config.detector.exec(content)) !== null) matches.push(regexMatchToPIIMatch(match));
156
+ return matches;
157
+ };
158
+ else detector = config.detector;
159
+ else {
160
+ const builtInType = config.piiType;
161
+ if (!BUILT_IN_DETECTORS[builtInType]) throw new Error(`Unknown PII type: ${config.piiType}. Must be one of: ${Object.keys(BUILT_IN_DETECTORS).join(", ")}, or provide a custom detector.`);
162
+ detector = BUILT_IN_DETECTORS[builtInType];
163
+ }
164
+ return {
165
+ piiType: config.piiType,
166
+ strategy: config.strategy,
167
+ detector
168
+ };
169
+ }
170
+ /**
171
+ * Apply redact strategy: replace with [REDACTED_TYPE]
172
+ */
173
+ function applyRedactStrategy(content, matches, piiType) {
174
+ let result = content;
175
+ for (let i = matches.length - 1; i >= 0; i--) {
176
+ const match = matches[i];
177
+ const replacement = `[REDACTED_${piiType.toUpperCase()}]`;
178
+ result = result.slice(0, match.start) + replacement + result.slice(match.end);
179
+ }
180
+ return result;
181
+ }
182
+ /**
183
+ * Apply mask strategy: partially mask PII (show last few characters)
184
+ */
185
+ function applyMaskStrategy(content, matches, piiType) {
186
+ let result = content;
187
+ for (let i = matches.length - 1; i >= 0; i--) {
188
+ const match = matches[i];
189
+ const text = match.text;
190
+ let masked;
191
+ if (piiType === "credit_card") {
192
+ const digits = text.replace(/\D/g, "");
193
+ const last4 = digits.slice(-4);
194
+ masked = `****-****-****-${last4}`;
195
+ } else if (piiType === "email") {
196
+ const [local, domain] = text.split("@");
197
+ if (local && domain) masked = `${local[0]}***@${domain}`;
198
+ else masked = "***";
199
+ } else {
200
+ const visibleChars = Math.min(4, text.length);
201
+ masked = `${"*".repeat(Math.max(0, text.length - visibleChars))}${text.slice(-visibleChars)}`;
202
+ }
203
+ result = result.slice(0, match.start) + masked + result.slice(match.end);
204
+ }
205
+ return result;
206
+ }
207
+ /**
208
+ * Apply hash strategy: replace with deterministic hash
209
+ */
210
+ function applyHashStrategy(content, matches, piiType) {
211
+ let result = content;
212
+ for (let i = matches.length - 1; i >= 0; i--) {
213
+ const match = matches[i];
214
+ const hash = (0, __langchain_core_utils_hash.sha256)(match.text).slice(0, 8);
215
+ const replacement = `<${piiType}_hash:${hash}>`;
216
+ result = result.slice(0, match.start) + replacement + result.slice(match.end);
217
+ }
218
+ return result;
219
+ }
220
+ /**
221
+ * Apply strategy to content based on matches
222
+ */
223
+ function applyStrategy(content, matches, strategy, piiType) {
224
+ if (matches.length === 0) return content;
225
+ switch (strategy) {
226
+ case "block": throw new PIIDetectionError(piiType, matches);
227
+ case "redact": return applyRedactStrategy(content, matches, piiType);
228
+ case "mask": return applyMaskStrategy(content, matches, piiType);
229
+ case "hash": return applyHashStrategy(content, matches, piiType);
230
+ default: throw new Error(`Unknown strategy: ${strategy}`);
231
+ }
232
+ }
233
+ /**
234
+ * Configuration schema for PII middleware
235
+ */
236
+ const contextSchema = zod_v3.z.object({
237
+ applyToInput: zod_v3.z.boolean().optional(),
238
+ applyToOutput: zod_v3.z.boolean().optional(),
239
+ applyToToolResults: zod_v3.z.boolean().optional()
240
+ });
241
+ /**
242
+ * Process content for PII detection and apply strategy
243
+ */
244
+ function processContent(content, rule) {
245
+ const matches = rule.detector(content);
246
+ if (matches.length === 0) return {
247
+ content,
248
+ matches: []
249
+ };
250
+ const sanitized = applyStrategy(content, matches, rule.strategy, rule.piiType);
251
+ return {
252
+ content: sanitized,
253
+ matches
254
+ };
255
+ }
256
+ /**
257
+ * Creates a middleware that detects and handles personally identifiable information (PII)
258
+ * in conversations.
259
+ *
260
+ * This middleware detects common PII types and applies configurable strategies to handle them.
261
+ * It can detect emails, credit cards, IP addresses, MAC addresses, and URLs in both user input
262
+ * and agent output.
263
+ *
264
+ * Built-in PII types:
265
+ * - `email`: Email addresses
266
+ * - `credit_card`: Credit card numbers (validated with Luhn algorithm)
267
+ * - `ip`: IP addresses (validated)
268
+ * - `mac_address`: MAC addresses
269
+ * - `url`: URLs (both `http`/`https` and bare URLs)
270
+ *
271
+ * Strategies:
272
+ * - `block`: Raise an exception when PII is detected
273
+ * - `redact`: Replace PII with `[REDACTED_TYPE]` placeholders
274
+ * - `mask`: Partially mask PII (e.g., `****-****-****-1234` for credit card)
275
+ * - `hash`: Replace PII with deterministic hash (e.g., `<email_hash:a1b2c3d4>`)
276
+ *
277
+ * Strategy Selection Guide:
278
+ * | Strategy | Preserves Identity? | Best For |
279
+ * | -------- | ------------------- | --------------------------------------- |
280
+ * | `block` | N/A | Avoid PII completely |
281
+ * | `redact` | No | General compliance, log sanitization |
282
+ * | `mask` | No | Human readability, customer service UIs |
283
+ * | `hash` | Yes (pseudonymous) | Analytics, debugging |
284
+ *
285
+ * @param piiType - Type of PII to detect. Can be a built-in type (`email`, `credit_card`, `ip`, `mac_address`, `url`) or a custom type name.
286
+ * @param options - Configuration options
287
+ * @param options.strategy - How to handle detected PII. Defaults to `"redact"`.
288
+ * @param options.detector - Custom detector function or regex pattern string. If not provided, uses built-in detector for the `piiType`.
289
+ * @param options.applyToInput - Whether to check user messages before model call. Defaults to `true`.
290
+ * @param options.applyToOutput - Whether to check AI messages after model call. Defaults to `false`.
291
+ * @param options.applyToToolResults - Whether to check tool result messages after tool execution. Defaults to `false`.
292
+ *
293
+ * @returns Middleware instance for use with `createAgent`
294
+ *
295
+ * @throws {PIIDetectionError} When PII is detected and strategy is `'block'`
296
+ * @throws {Error} If `piiType` is not built-in and no detector is provided
297
+ *
298
+ * @example Basic usage
299
+ * ```typescript
300
+ * import { piiMiddleware } from "langchain";
301
+ * import { createAgent } from "langchain";
302
+ *
303
+ * // Redact all emails in user input
304
+ * const agent = createAgent({
305
+ * model: "openai:gpt-4",
306
+ * middleware: [
307
+ * piiMiddleware("email", { strategy: "redact" }),
308
+ * ],
309
+ * });
310
+ * ```
311
+ *
312
+ * @example Different strategies for different PII types
313
+ * ```typescript
314
+ * const agent = createAgent({
315
+ * model: "openai:gpt-4o",
316
+ * middleware: [
317
+ * piiMiddleware("credit_card", { strategy: "mask" }),
318
+ * piiMiddleware("url", { strategy: "redact" }),
319
+ * piiMiddleware("ip", { strategy: "hash" }),
320
+ * ],
321
+ * });
322
+ * ```
323
+ *
324
+ * @example Custom PII type with regex
325
+ * ```typescript
326
+ * const agent = createAgent({
327
+ * model: "openai:gpt-4",
328
+ * middleware: [
329
+ * piiMiddleware("api_key", {
330
+ * detector: "sk-[a-zA-Z0-9]{32}",
331
+ * strategy: "block",
332
+ * }),
333
+ * ],
334
+ * });
335
+ * ```
336
+ *
337
+ * @public
338
+ */
339
+ function piiMiddleware(piiType, options = {}) {
340
+ const { strategy = "redact", detector } = options;
341
+ const resolvedRule = resolveRedactionRule({
342
+ piiType,
343
+ strategy,
344
+ detector
345
+ });
346
+ const middlewareName = `PIIMiddleware[${resolvedRule.piiType}]`;
347
+ return require_middleware.createMiddleware({
348
+ name: middlewareName,
349
+ contextSchema,
350
+ beforeModel: async (state, runtime) => {
351
+ const applyToInput = runtime.context.applyToInput ?? options.applyToInput ?? true;
352
+ const applyToToolResults = runtime.context.applyToToolResults ?? options.applyToToolResults ?? false;
353
+ if (!applyToInput && !applyToToolResults) return;
354
+ const messages = state.messages;
355
+ if (!messages || messages.length === 0) return;
356
+ const newMessages = [...messages];
357
+ let anyModified = false;
358
+ if (applyToInput) {
359
+ let lastUserIdx = null;
360
+ for (let i = messages.length - 1; i >= 0; i--) if (__langchain_core_messages.HumanMessage.isInstance(messages[i])) {
361
+ lastUserIdx = i;
362
+ break;
363
+ }
364
+ if (lastUserIdx !== null) {
365
+ const lastUserMsg = messages[lastUserIdx];
366
+ if (lastUserMsg && lastUserMsg.content) {
367
+ const content = String(lastUserMsg.content);
368
+ const { content: newContent, matches } = processContent(content, resolvedRule);
369
+ if (matches.length > 0) {
370
+ newMessages[lastUserIdx] = new __langchain_core_messages.HumanMessage({
371
+ content: newContent,
372
+ id: lastUserMsg.id,
373
+ name: lastUserMsg.name
374
+ });
375
+ anyModified = true;
376
+ }
377
+ }
378
+ }
379
+ }
380
+ if (applyToToolResults) {
381
+ let lastAiIdx = null;
382
+ for (let i = messages.length - 1; i >= 0; i--) if (__langchain_core_messages.AIMessage.isInstance(messages[i])) {
383
+ lastAiIdx = i;
384
+ break;
385
+ }
386
+ if (lastAiIdx !== null) for (let i = lastAiIdx + 1; i < messages.length; i++) {
387
+ const msg = messages[i];
388
+ if (__langchain_core_messages.ToolMessage.isInstance(msg)) {
389
+ if (!msg.content) continue;
390
+ const content = String(msg.content);
391
+ const { content: newContent, matches } = processContent(content, resolvedRule);
392
+ if (matches.length > 0) {
393
+ newMessages[i] = new __langchain_core_messages.ToolMessage({
394
+ content: newContent,
395
+ id: msg.id,
396
+ name: msg.name,
397
+ tool_call_id: msg.tool_call_id
398
+ });
399
+ anyModified = true;
400
+ }
401
+ }
402
+ }
403
+ }
404
+ if (anyModified) return { messages: newMessages };
405
+ },
406
+ afterModel: async (state, runtime) => {
407
+ const applyToOutput = runtime.context.applyToOutput ?? options.applyToOutput ?? false;
408
+ if (!applyToOutput) return;
409
+ const messages = state.messages;
410
+ if (!messages || messages.length === 0) return;
411
+ let lastAiIdx = null;
412
+ let lastAiMsg = null;
413
+ for (let i = messages.length - 1; i >= 0; i--) if (__langchain_core_messages.AIMessage.isInstance(messages[i])) {
414
+ lastAiMsg = messages[i];
415
+ lastAiIdx = i;
416
+ break;
417
+ }
418
+ if (lastAiIdx === null || !lastAiMsg || !lastAiMsg.content) return;
419
+ const content = String(lastAiMsg.content);
420
+ const { content: newContent, matches } = processContent(content, resolvedRule);
421
+ if (matches.length === 0) return;
422
+ const updatedMessage = new __langchain_core_messages.AIMessage({
423
+ content: newContent,
424
+ id: lastAiMsg.id,
425
+ name: lastAiMsg.name,
426
+ tool_calls: lastAiMsg.tool_calls
427
+ });
428
+ const newMessages = [...messages];
429
+ newMessages[lastAiIdx] = updatedMessage;
430
+ return { messages: newMessages };
431
+ }
432
+ });
433
+ }
434
+
435
+ //#endregion
436
+ exports.PIIDetectionError = PIIDetectionError;
437
+ exports.applyStrategy = applyStrategy;
438
+ exports.detectCreditCard = detectCreditCard;
439
+ exports.detectEmail = detectEmail;
440
+ exports.detectIP = detectIP;
441
+ exports.detectMacAddress = detectMacAddress;
442
+ exports.detectUrl = detectUrl;
443
+ exports.piiMiddleware = piiMiddleware;
444
+ exports.resolveRedactionRule = resolveRedactionRule;
445
+ //# sourceMappingURL=pii.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pii.cjs","names":["piiType: string","matches: PIIMatch[]","cardNumber: string","match: RegExpMatchArray","content: string","match: RegExpMatchArray | null","BUILT_IN_DETECTORS: Record<BuiltInPIIType, PIIDetector>","config: RedactionRuleConfig","detector: PIIDetector","masked: string","strategy: PIIStrategy","z","rule: ResolvedRedactionRule","piiType: BuiltInPIIType | string","options: {\n strategy?: PIIStrategy;\n detector?: Detector;\n applyToInput?: boolean;\n applyToOutput?: boolean;\n applyToToolResults?: boolean;\n }","createMiddleware","lastUserIdx: number | null","HumanMessage","lastAiIdx: number | null","AIMessage","ToolMessage","lastAiMsg: AIMessage | null"],"sources":["../../../src/agents/middleware/pii.ts"],"sourcesContent":["import { z } from \"zod/v3\";\nimport { sha256 } from \"@langchain/core/utils/hash\";\nimport { AIMessage, HumanMessage, ToolMessage } from \"@langchain/core/messages\";\nimport type { InferInteropZodInput } from \"@langchain/core/utils/types\";\n\nimport { createMiddleware } from \"../middleware.js\";\n\n/**\n * Represents a detected PII match in content\n */\nexport interface PIIMatch {\n /**\n * The matched text\n */\n text: string;\n /**\n * The start index of the match\n */\n start: number;\n /**\n * The end index of the match\n */\n end: number;\n}\n\n/**\n * Error thrown when PII is detected and strategy is 'block'\n */\nexport class PIIDetectionError extends Error {\n constructor(\n public readonly piiType: string,\n public readonly matches: PIIMatch[]\n ) {\n super(`PII detected: ${piiType} found ${matches.length} occurrence(s)`);\n this.name = \"PIIDetectionError\";\n }\n}\n\n/**\n * Strategy for handling detected PII\n */\nexport type PIIStrategy = \"block\" | \"redact\" | \"mask\" | \"hash\";\n\n/**\n * Built-in PII types\n */\nexport type BuiltInPIIType =\n | \"email\"\n | \"credit_card\"\n | \"ip\"\n | \"mac_address\"\n | \"url\";\n\n/**\n * Custom detector function that takes content and returns matches\n */\nexport type PIIDetector = (content: string) => PIIMatch[];\nexport type Detector = PIIDetector | RegExp | string;\n\n/**\n * Configuration for a redaction rule\n */\nexport interface RedactionRuleConfig {\n /**\n * Type of PII to detect (built-in or custom name)\n */\n piiType: BuiltInPIIType | string;\n /**\n * Strategy for handling detected PII\n */\n strategy: PIIStrategy;\n /**\n * Custom detector function or regex pattern string\n */\n detector?: Detector;\n}\n\n/**\n * Resolved redaction rule with a concrete detector function\n */\nexport interface ResolvedRedactionRule {\n piiType: string;\n strategy: PIIStrategy;\n detector: PIIDetector;\n}\n\n/**\n * Email detection regex pattern\n */\nconst EMAIL_PATTERN = /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b/g;\n\n/**\n * Credit card detection regex pattern (basic, will be validated with Luhn)\n */\nconst CREDIT_CARD_PATTERN = /\\b(?:\\d{4}[-\\s]?){3}\\d{4}\\b/g;\n\n/**\n * IP address detection regex pattern\n */\nconst IP_PATTERN =\n /\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b/g;\n\n/**\n * MAC address detection regex pattern\n */\nconst MAC_ADDRESS_PATTERN = /\\b(?:[0-9A-Fa-f]{2}[:-]){5}(?:[0-9A-Fa-f]{2})\\b/g;\n\n/**\n * URL detection regex pattern\n */\nconst URL_PATTERN = /(?:https?:\\/\\/|www\\.)[^\\s<>\"{}|\\\\^`[\\]]+/gi;\n\n/**\n * Luhn algorithm for credit card validation\n */\nfunction luhnCheck(cardNumber: string): boolean {\n const digits = cardNumber.replace(/\\D/g, \"\");\n let sum = 0;\n let isEven = false;\n\n for (let i = digits.length - 1; i >= 0; i--) {\n let digit = parseInt(digits[i], 10);\n\n if (isEven) {\n digit *= 2;\n if (digit > 9) {\n digit -= 9;\n }\n }\n\n sum += digit;\n isEven = !isEven;\n }\n\n return sum % 10 === 0;\n}\n\n/**\n * Convert regex match to PIIMatch\n */\nfunction regexMatchToPIIMatch(match: RegExpMatchArray): PIIMatch {\n return {\n text: match[0],\n start: match.index ?? 0,\n end: (match.index ?? 0) + match[0].length,\n };\n}\n\n/**\n * Detect email addresses in content\n */\nexport function detectEmail(content: string): PIIMatch[] {\n const matches: PIIMatch[] = [];\n const regex = new RegExp(EMAIL_PATTERN);\n let match: RegExpMatchArray | null;\n\n while ((match = regex.exec(content)) !== null) {\n matches.push(regexMatchToPIIMatch(match));\n }\n\n return matches;\n}\n\n/**\n * Detect credit card numbers in content (validated with Luhn algorithm)\n */\nexport function detectCreditCard(content: string): PIIMatch[] {\n const matches: PIIMatch[] = [];\n const regex = new RegExp(CREDIT_CARD_PATTERN);\n let match: RegExpMatchArray | null;\n\n while ((match = regex.exec(content)) !== null) {\n const cardNumber = match[0].replace(/\\D/g, \"\");\n // Credit cards are typically 13-19 digits\n if (\n cardNumber.length >= 13 &&\n cardNumber.length <= 19 &&\n luhnCheck(cardNumber)\n ) {\n matches.push(regexMatchToPIIMatch(match));\n }\n }\n\n return matches;\n}\n\n/**\n * Detect IP addresses in content (validated)\n */\nexport function detectIP(content: string): PIIMatch[] {\n const matches: PIIMatch[] = [];\n const regex = new RegExp(IP_PATTERN);\n let match: RegExpMatchArray | null;\n\n while ((match = regex.exec(content)) !== null) {\n const ip = match[0];\n // Additional validation: each octet should be 0-255\n const parts = ip.split(\".\");\n if (\n parts.length === 4 &&\n parts.every((part) => {\n const num = parseInt(part, 10);\n return num >= 0 && num <= 255;\n })\n ) {\n matches.push(regexMatchToPIIMatch(match));\n }\n }\n\n return matches;\n}\n\n/**\n * Detect MAC addresses in content\n */\nexport function detectMacAddress(content: string): PIIMatch[] {\n const matches: PIIMatch[] = [];\n const regex = new RegExp(MAC_ADDRESS_PATTERN);\n let match: RegExpMatchArray | null;\n\n while ((match = regex.exec(content)) !== null) {\n matches.push(regexMatchToPIIMatch(match));\n }\n\n return matches;\n}\n\n/**\n * Detect URLs in content\n */\nexport function detectUrl(content: string): PIIMatch[] {\n const matches: PIIMatch[] = [];\n const regex = new RegExp(URL_PATTERN);\n let match: RegExpMatchArray | null;\n\n while ((match = regex.exec(content)) !== null) {\n matches.push(regexMatchToPIIMatch(match));\n }\n\n return matches;\n}\n\n/**\n * Built-in detector map\n */\nconst BUILT_IN_DETECTORS: Record<BuiltInPIIType, PIIDetector> = {\n email: detectEmail,\n credit_card: detectCreditCard,\n ip: detectIP,\n mac_address: detectMacAddress,\n url: detectUrl,\n};\n\n/**\n * Resolve a redaction rule to a concrete detector function\n */\nexport function resolveRedactionRule(\n config: RedactionRuleConfig\n): ResolvedRedactionRule {\n let detector: PIIDetector;\n\n if (config.detector) {\n if (typeof config.detector === \"string\") {\n // Regex pattern string\n const regex = new RegExp(config.detector, \"g\");\n detector = (content: string) => {\n const matches: PIIMatch[] = [];\n let match: RegExpMatchArray | null;\n const regexCopy = new RegExp(regex);\n\n while ((match = regexCopy.exec(content)) !== null) {\n matches.push(regexMatchToPIIMatch(match));\n }\n\n return matches;\n };\n // eslint-disable-next-line no-instanceof/no-instanceof\n } else if (config.detector instanceof RegExp) {\n detector = (content: string) => {\n // eslint-disable-next-line no-instanceof/no-instanceof\n if (!(config.detector instanceof RegExp)) {\n throw new Error(\"Detector is required\");\n }\n const matches: PIIMatch[] = [];\n let match: RegExpMatchArray | null;\n while ((match = config.detector.exec(content)) !== null) {\n matches.push(regexMatchToPIIMatch(match));\n }\n\n return matches;\n };\n } else {\n detector = config.detector;\n }\n } else {\n // Use built-in detector\n const builtInType = config.piiType as BuiltInPIIType;\n if (!BUILT_IN_DETECTORS[builtInType]) {\n throw new Error(\n `Unknown PII type: ${config.piiType}. Must be one of: ${Object.keys(\n BUILT_IN_DETECTORS\n ).join(\", \")}, or provide a custom detector.`\n );\n }\n detector = BUILT_IN_DETECTORS[builtInType];\n }\n\n return {\n piiType: config.piiType,\n strategy: config.strategy,\n detector,\n };\n}\n\n/**\n * Apply redact strategy: replace with [REDACTED_TYPE]\n */\nfunction applyRedactStrategy(\n content: string,\n matches: PIIMatch[],\n piiType: string\n): string {\n let result = content;\n // Process matches in reverse order to preserve indices\n for (let i = matches.length - 1; i >= 0; i--) {\n const match = matches[i];\n const replacement = `[REDACTED_${piiType.toUpperCase()}]`;\n result =\n result.slice(0, match.start) + replacement + result.slice(match.end);\n }\n return result;\n}\n\n/**\n * Apply mask strategy: partially mask PII (show last few characters)\n */\nfunction applyMaskStrategy(\n content: string,\n matches: PIIMatch[],\n piiType: string\n): string {\n let result = content;\n // Process matches in reverse order to preserve indices\n for (let i = matches.length - 1; i >= 0; i--) {\n const match = matches[i];\n const text = match.text;\n let masked: string;\n\n if (piiType === \"credit_card\") {\n // Show last 4 digits: ****-****-****-1234\n const digits = text.replace(/\\D/g, \"\");\n const last4 = digits.slice(-4);\n masked = `****-****-****-${last4}`;\n } else if (piiType === \"email\") {\n // Show first char and domain: j***@example.com\n const [local, domain] = text.split(\"@\");\n if (local && domain) {\n masked = `${local[0]}***@${domain}`;\n } else {\n masked = \"***\";\n }\n } else {\n // Default: show last 4 characters\n const visibleChars = Math.min(4, text.length);\n masked = `${\"*\".repeat(\n Math.max(0, text.length - visibleChars)\n )}${text.slice(-visibleChars)}`;\n }\n\n result = result.slice(0, match.start) + masked + result.slice(match.end);\n }\n return result;\n}\n\n/**\n * Apply hash strategy: replace with deterministic hash\n */\nfunction applyHashStrategy(\n content: string,\n matches: PIIMatch[],\n piiType: string\n): string {\n let result = content;\n // Process matches in reverse order to preserve indices\n for (let i = matches.length - 1; i >= 0; i--) {\n const match = matches[i];\n const hash = sha256(match.text).slice(0, 8);\n const replacement = `<${piiType}_hash:${hash}>`;\n result =\n result.slice(0, match.start) + replacement + result.slice(match.end);\n }\n return result;\n}\n\n/**\n * Apply strategy to content based on matches\n */\nexport function applyStrategy(\n content: string,\n matches: PIIMatch[],\n strategy: PIIStrategy,\n piiType: string\n): string {\n if (matches.length === 0) {\n return content;\n }\n\n switch (strategy) {\n case \"block\":\n throw new PIIDetectionError(piiType, matches);\n case \"redact\":\n return applyRedactStrategy(content, matches, piiType);\n case \"mask\":\n return applyMaskStrategy(content, matches, piiType);\n case \"hash\":\n return applyHashStrategy(content, matches, piiType);\n default:\n throw new Error(`Unknown strategy: ${strategy}`);\n }\n}\n\n/**\n * Configuration schema for PII middleware\n */\nconst contextSchema = z.object({\n /**\n * Whether to check user messages before model call\n */\n applyToInput: z.boolean().optional(),\n /**\n * Whether to check AI messages after model call\n */\n applyToOutput: z.boolean().optional(),\n /**\n * Whether to check tool result messages after tool execution\n */\n applyToToolResults: z.boolean().optional(),\n});\n\nexport type PIIMiddlewareConfig = InferInteropZodInput<typeof contextSchema>;\n\n/**\n * Process content for PII detection and apply strategy\n */\nfunction processContent(\n content: string,\n rule: ResolvedRedactionRule\n): { content: string; matches: PIIMatch[] } {\n const matches = rule.detector(content);\n if (matches.length === 0) {\n return { content, matches: [] };\n }\n\n const sanitized = applyStrategy(\n content,\n matches,\n rule.strategy,\n rule.piiType\n );\n return { content: sanitized, matches };\n}\n\n/**\n * Creates a middleware that detects and handles personally identifiable information (PII)\n * in conversations.\n *\n * This middleware detects common PII types and applies configurable strategies to handle them.\n * It can detect emails, credit cards, IP addresses, MAC addresses, and URLs in both user input\n * and agent output.\n *\n * Built-in PII types:\n * - `email`: Email addresses\n * - `credit_card`: Credit card numbers (validated with Luhn algorithm)\n * - `ip`: IP addresses (validated)\n * - `mac_address`: MAC addresses\n * - `url`: URLs (both `http`/`https` and bare URLs)\n *\n * Strategies:\n * - `block`: Raise an exception when PII is detected\n * - `redact`: Replace PII with `[REDACTED_TYPE]` placeholders\n * - `mask`: Partially mask PII (e.g., `****-****-****-1234` for credit card)\n * - `hash`: Replace PII with deterministic hash (e.g., `<email_hash:a1b2c3d4>`)\n *\n * Strategy Selection Guide:\n * | Strategy | Preserves Identity? | Best For |\n * | -------- | ------------------- | --------------------------------------- |\n * | `block` | N/A | Avoid PII completely |\n * | `redact` | No | General compliance, log sanitization |\n * | `mask` | No | Human readability, customer service UIs |\n * | `hash` | Yes (pseudonymous) | Analytics, debugging |\n *\n * @param piiType - Type of PII to detect. Can be a built-in type (`email`, `credit_card`, `ip`, `mac_address`, `url`) or a custom type name.\n * @param options - Configuration options\n * @param options.strategy - How to handle detected PII. Defaults to `\"redact\"`.\n * @param options.detector - Custom detector function or regex pattern string. If not provided, uses built-in detector for the `piiType`.\n * @param options.applyToInput - Whether to check user messages before model call. Defaults to `true`.\n * @param options.applyToOutput - Whether to check AI messages after model call. Defaults to `false`.\n * @param options.applyToToolResults - Whether to check tool result messages after tool execution. Defaults to `false`.\n *\n * @returns Middleware instance for use with `createAgent`\n *\n * @throws {PIIDetectionError} When PII is detected and strategy is `'block'`\n * @throws {Error} If `piiType` is not built-in and no detector is provided\n *\n * @example Basic usage\n * ```typescript\n * import { piiMiddleware } from \"langchain\";\n * import { createAgent } from \"langchain\";\n *\n * // Redact all emails in user input\n * const agent = createAgent({\n * model: \"openai:gpt-4\",\n * middleware: [\n * piiMiddleware(\"email\", { strategy: \"redact\" }),\n * ],\n * });\n * ```\n *\n * @example Different strategies for different PII types\n * ```typescript\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * middleware: [\n * piiMiddleware(\"credit_card\", { strategy: \"mask\" }),\n * piiMiddleware(\"url\", { strategy: \"redact\" }),\n * piiMiddleware(\"ip\", { strategy: \"hash\" }),\n * ],\n * });\n * ```\n *\n * @example Custom PII type with regex\n * ```typescript\n * const agent = createAgent({\n * model: \"openai:gpt-4\",\n * middleware: [\n * piiMiddleware(\"api_key\", {\n * detector: \"sk-[a-zA-Z0-9]{32}\",\n * strategy: \"block\",\n * }),\n * ],\n * });\n * ```\n *\n * @public\n */\nexport function piiMiddleware(\n piiType: BuiltInPIIType | string,\n options: {\n strategy?: PIIStrategy;\n detector?: Detector;\n applyToInput?: boolean;\n applyToOutput?: boolean;\n applyToToolResults?: boolean;\n } = {}\n): ReturnType<typeof createMiddleware> {\n const { strategy = \"redact\", detector } = options;\n const resolvedRule = resolveRedactionRule({\n piiType,\n strategy,\n detector,\n });\n\n const middlewareName = `PIIMiddleware[${resolvedRule.piiType}]`;\n\n return createMiddleware({\n name: middlewareName,\n contextSchema,\n beforeModel: async (state, runtime) => {\n const applyToInput =\n runtime.context.applyToInput ?? options.applyToInput ?? true;\n const applyToToolResults =\n runtime.context.applyToToolResults ??\n options.applyToToolResults ??\n false;\n\n if (!applyToInput && !applyToToolResults) {\n return;\n }\n\n const messages = state.messages;\n if (!messages || messages.length === 0) {\n return;\n }\n\n const newMessages = [...messages];\n let anyModified = false;\n\n // Check user input if enabled\n if (applyToInput) {\n // Get last user message\n let lastUserIdx: number | null = null;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (HumanMessage.isInstance(messages[i])) {\n lastUserIdx = i;\n break;\n }\n }\n\n if (lastUserIdx !== null) {\n const lastUserMsg = messages[lastUserIdx];\n if (lastUserMsg && lastUserMsg.content) {\n const content = String(lastUserMsg.content);\n const { content: newContent, matches } = processContent(\n content,\n resolvedRule\n );\n\n if (matches.length > 0) {\n newMessages[lastUserIdx] = new HumanMessage({\n content: newContent,\n id: lastUserMsg.id,\n name: lastUserMsg.name,\n });\n anyModified = true;\n }\n }\n }\n }\n\n // Check tool results if enabled\n if (applyToToolResults) {\n // Find the last AIMessage, then process all ToolMessage objects after it\n let lastAiIdx: number | null = null;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (AIMessage.isInstance(messages[i])) {\n lastAiIdx = i;\n break;\n }\n }\n\n if (lastAiIdx !== null) {\n // Get all tool messages after the last AI message\n for (let i = lastAiIdx + 1; i < messages.length; i++) {\n const msg = messages[i];\n if (ToolMessage.isInstance(msg)) {\n if (!msg.content) {\n continue;\n }\n\n const content = String(msg.content);\n const { content: newContent, matches } = processContent(\n content,\n resolvedRule\n );\n\n if (matches.length > 0) {\n newMessages[i] = new ToolMessage({\n content: newContent,\n id: msg.id,\n name: msg.name,\n tool_call_id: msg.tool_call_id,\n });\n anyModified = true;\n }\n }\n }\n }\n }\n\n if (anyModified) {\n return { messages: newMessages };\n }\n\n return;\n },\n afterModel: async (state, runtime) => {\n const applyToOutput =\n runtime.context.applyToOutput ?? options.applyToOutput ?? false;\n\n if (!applyToOutput) {\n return;\n }\n\n const messages = state.messages;\n if (!messages || messages.length === 0) {\n return;\n }\n\n // Get last AI message\n let lastAiIdx: number | null = null;\n let lastAiMsg: AIMessage | null = null;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (AIMessage.isInstance(messages[i])) {\n lastAiMsg = messages[i];\n lastAiIdx = i;\n break;\n }\n }\n\n if (lastAiIdx === null || !lastAiMsg || !lastAiMsg.content) {\n return;\n }\n\n // Detect PII in message content\n const content = String(lastAiMsg.content);\n const { content: newContent, matches } = processContent(\n content,\n resolvedRule\n );\n\n if (matches.length === 0) {\n return;\n }\n\n // Create updated message\n const updatedMessage = new AIMessage({\n content: newContent,\n id: lastAiMsg.id,\n name: lastAiMsg.name,\n tool_calls: lastAiMsg.tool_calls,\n });\n\n // Return updated messages\n const newMessages = [...messages];\n newMessages[lastAiIdx] = updatedMessage;\n return { messages: newMessages };\n },\n });\n}\n"],"mappings":"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"}