agentshield-sdk 7.3.0 → 7.4.0

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 (43) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +36 -7
  3. package/package.json +7 -3
  4. package/src/agent-protocol.js +4 -0
  5. package/src/allowlist.js +605 -603
  6. package/src/audit-streaming.js +486 -469
  7. package/src/audit.js +1 -1
  8. package/src/behavior-profiling.js +299 -289
  9. package/src/behavioral-dna.js +4 -9
  10. package/src/canary.js +273 -271
  11. package/src/compliance.js +619 -617
  12. package/src/confidence-tuning.js +328 -324
  13. package/src/context-scoring.js +362 -360
  14. package/src/cost-optimizer.js +1024 -1024
  15. package/src/detector-core.js +186 -0
  16. package/src/distributed.js +5 -1
  17. package/src/embedding.js +310 -307
  18. package/src/herd-immunity.js +12 -12
  19. package/src/honeypot.js +332 -328
  20. package/src/integrations.js +1 -2
  21. package/src/intent-firewall.js +14 -14
  22. package/src/llm-redteam.js +678 -670
  23. package/src/main.js +10 -0
  24. package/src/middleware.js +5 -2
  25. package/src/model-fingerprint.js +1059 -1042
  26. package/src/multi-agent-trust.js +459 -453
  27. package/src/multi-agent.js +1 -1
  28. package/src/normalizer.js +734 -0
  29. package/src/pii.js +4 -0
  30. package/src/policy-dsl.js +775 -775
  31. package/src/presets.js +409 -409
  32. package/src/production.js +22 -9
  33. package/src/redteam.js +475 -475
  34. package/src/response-handler.js +436 -429
  35. package/src/scanners.js +358 -357
  36. package/src/self-healing.js +368 -363
  37. package/src/semantic.js +339 -339
  38. package/src/shield-score.js +250 -250
  39. package/src/sso-saml.js +8 -4
  40. package/src/testing.js +24 -2
  41. package/src/tool-guard.js +412 -412
  42. package/src/watermark.js +242 -235
  43. package/src/worker-scanner.js +608 -601
package/src/audit.js CHANGED
@@ -602,7 +602,7 @@ function runAuditCLI() {
602
602
  });
603
603
 
604
604
  const report = audit.run();
605
- console.log(report.formatReport());
605
+ console.log('[Agent Shield] Audit Report:\n' + report.formatReport());
606
606
  return report;
607
607
  }
608
608
 
@@ -1,289 +1,299 @@
1
- 'use strict';
2
-
3
- /**
4
- * Agent Shield — Agent Behavior Profiling (v3.0)
5
- *
6
- * Establishes baselines for normal agent behavior and detects anomalies
7
- * that may indicate compromise, drift, or attack influence.
8
- *
9
- * Tracks: response patterns, tool usage, topic distribution, timing,
10
- * output length, sentiment shifts, and more.
11
- *
12
- * All processing runs locally — no data ever leaves your environment.
13
- */
14
-
15
- // =========================================================================
16
- // STATISTICAL HELPERS
17
- // =========================================================================
18
-
19
- /**
20
- * Calculate mean of an array.
21
- * @param {number[]} arr
22
- * @returns {number}
23
- */
24
- function mean(arr) {
25
- return arr.length > 0 ? arr.reduce((a, b) => a + b, 0) / arr.length : 0;
26
- }
27
-
28
- /**
29
- * Calculate standard deviation.
30
- * @param {number[]} arr
31
- * @returns {number}
32
- */
33
- function stdDev(arr) {
34
- if (arr.length < 2) return 0;
35
- const m = mean(arr);
36
- const squaredDiffs = arr.map(x => (x - m) ** 2);
37
- return Math.sqrt(squaredDiffs.reduce((a, b) => a + b, 0) / (arr.length - 1));
38
- }
39
-
40
- /**
41
- * Check if a value is anomalous (beyond N standard deviations from mean).
42
- * @param {number} value
43
- * @param {number} m - Mean.
44
- * @param {number} sd - Standard deviation.
45
- * @param {number} [threshold=2] - Number of standard deviations.
46
- * @returns {boolean}
47
- */
48
- function isAnomaly(value, m, sd, threshold = 2) {
49
- if (sd === 0) return value !== m;
50
- return Math.abs(value - m) > threshold * sd;
51
- }
52
-
53
- // =========================================================================
54
- // BEHAVIOR PROFILE
55
- // =========================================================================
56
-
57
- /**
58
- * Maintains a statistical profile of agent behavior.
59
- */
60
- class BehaviorProfile {
61
- /**
62
- * @param {object} [options]
63
- * @param {number} [options.windowSize=200] - Number of observations to maintain.
64
- * @param {number} [options.learningPeriod=20] - Observations before anomaly detection activates.
65
- * @param {number} [options.anomalyThreshold=2.5] - Standard deviations for anomaly detection.
66
- */
67
- constructor(options = {}) {
68
- this.windowSize = options.windowSize || 200;
69
- this.learningPeriod = options.learningPeriod || 20;
70
- this.anomalyThreshold = options.anomalyThreshold || 2.5;
71
-
72
- this._metrics = {
73
- responseLength: [],
74
- responseTime: [],
75
- toolCallCount: [],
76
- threatScore: [],
77
- topicEntropy: []
78
- };
79
-
80
- this._toolUsage = {};
81
- this._topicDistribution = {};
82
- this._totalObservations = 0;
83
- this._anomalies = [];
84
-
85
- console.log('[Agent Shield] BehaviorProfile initialized (windowSize: %d, learningPeriod: %d)', this.windowSize, this.learningPeriod);
86
- }
87
-
88
- /**
89
- * Record an observation of agent behavior.
90
- *
91
- * @param {object} observation
92
- * @param {number} [observation.responseLength] - Length of agent response.
93
- * @param {number} [observation.responseTimeMs] - Time taken to respond.
94
- * @param {string[]} [observation.toolsCalled] - Tools used in this turn.
95
- * @param {number} [observation.threatScore] - Threat score from scanning.
96
- * @param {string} [observation.topic] - Detected topic/category.
97
- * @returns {object} { anomalies: Array, isLearning: boolean }
98
- */
99
- record(observation) {
100
- this._totalObservations++;
101
-
102
- // Record metrics
103
- if (observation.responseLength !== undefined) {
104
- this._addMetric('responseLength', observation.responseLength);
105
- }
106
- if (observation.responseTimeMs !== undefined) {
107
- this._addMetric('responseTime', observation.responseTimeMs);
108
- }
109
- if (observation.toolsCalled) {
110
- this._addMetric('toolCallCount', observation.toolsCalled.length);
111
- for (const tool of observation.toolsCalled) {
112
- this._toolUsage[tool] = (this._toolUsage[tool] || 0) + 1;
113
- }
114
- }
115
- if (observation.threatScore !== undefined) {
116
- this._addMetric('threatScore', observation.threatScore);
117
- }
118
- if (observation.topic) {
119
- this._topicDistribution[observation.topic] = (this._topicDistribution[observation.topic] || 0) + 1;
120
- }
121
-
122
- // Check for anomalies (only after learning period)
123
- const isLearning = this._totalObservations < this.learningPeriod;
124
- const anomalies = isLearning ? [] : this._detectAnomalies(observation);
125
-
126
- if (anomalies.length > 0) {
127
- this._anomalies.push({
128
- timestamp: Date.now(),
129
- observation: this._totalObservations,
130
- anomalies
131
- });
132
- }
133
-
134
- return { anomalies, isLearning };
135
- }
136
-
137
- /**
138
- * Get the current behavior baseline.
139
- * @returns {object}
140
- */
141
- getBaseline() {
142
- const baseline = {};
143
- for (const [metric, values] of Object.entries(this._metrics)) {
144
- if (values.length > 0) {
145
- baseline[metric] = {
146
- mean: Math.round(mean(values) * 100) / 100,
147
- stdDev: Math.round(stdDev(values) * 100) / 100,
148
- min: Math.min(...values),
149
- max: Math.max(...values),
150
- samples: values.length
151
- };
152
- }
153
- }
154
- return baseline;
155
- }
156
-
157
- /**
158
- * Get a full behavior report.
159
- * @returns {object}
160
- */
161
- getReport() {
162
- return {
163
- totalObservations: this._totalObservations,
164
- isLearning: this._totalObservations < this.learningPeriod,
165
- baseline: this.getBaseline(),
166
- toolUsage: { ...this._toolUsage },
167
- topicDistribution: { ...this._topicDistribution },
168
- anomalyCount: this._anomalies.length,
169
- recentAnomalies: this._anomalies.slice(-10),
170
- riskLevel: this._calculateRiskLevel()
171
- };
172
- }
173
-
174
- /**
175
- * Check if the agent appears to be behaving normally.
176
- * @returns {object} { normal: boolean, riskLevel, concerns: string[] }
177
- */
178
- healthCheck() {
179
- const concerns = [];
180
- const report = this.getReport();
181
-
182
- if (report.isLearning) {
183
- return { normal: true, riskLevel: 'unknown', concerns: ['Still in learning period.'] };
184
- }
185
-
186
- // Check for sudden tool usage changes
187
- const totalToolCalls = Object.values(this._toolUsage).reduce((a, b) => a + b, 0);
188
- if (totalToolCalls > 0) {
189
- for (const [tool, count] of Object.entries(this._toolUsage)) {
190
- const ratio = count / totalToolCalls;
191
- if (ratio > 0.7 && totalToolCalls > 10) {
192
- concerns.push(`Tool "${tool}" dominates usage at ${(ratio * 100).toFixed(0)}%.`);
193
- }
194
- }
195
- }
196
-
197
- // Check for high threat score trend
198
- const recentThreats = this._metrics.threatScore.slice(-20);
199
- if (recentThreats.length >= 5 && mean(recentThreats) > 0.5) {
200
- concerns.push('Recent threat scores are elevated.');
201
- }
202
-
203
- // Check for anomaly frequency
204
- const recentAnomalies = this._anomalies.filter(a => Date.now() - a.timestamp < 300000);
205
- if (recentAnomalies.length > 5) {
206
- concerns.push(`${recentAnomalies.length} anomalies in the last 5 minutes.`);
207
- }
208
-
209
- return {
210
- normal: concerns.length === 0,
211
- riskLevel: report.riskLevel,
212
- concerns
213
- };
214
- }
215
-
216
- /** Reset the profile. */
217
- reset() {
218
- for (const key of Object.keys(this._metrics)) {
219
- this._metrics[key] = [];
220
- }
221
- this._toolUsage = {};
222
- this._topicDistribution = {};
223
- this._totalObservations = 0;
224
- this._anomalies = [];
225
- }
226
-
227
- /** @private */
228
- _addMetric(name, value) {
229
- if (!this._metrics[name]) this._metrics[name] = [];
230
- this._metrics[name].push(value);
231
- if (this._metrics[name].length > this.windowSize) {
232
- this._metrics[name].shift();
233
- }
234
- }
235
-
236
- /** @private */
237
- _detectAnomalies(observation) {
238
- const anomalies = [];
239
-
240
- const checks = [
241
- { metric: 'responseLength', value: observation.responseLength, label: 'Response length' },
242
- { metric: 'responseTime', value: observation.responseTimeMs, label: 'Response time' },
243
- { metric: 'toolCallCount', value: observation.toolsCalled ? observation.toolsCalled.length : undefined, label: 'Tool call count' },
244
- { metric: 'threatScore', value: observation.threatScore, label: 'Threat score' }
245
- ];
246
-
247
- for (const check of checks) {
248
- if (check.value === undefined) continue;
249
-
250
- const values = this._metrics[check.metric];
251
- if (values.length < this.learningPeriod) continue;
252
-
253
- const m = mean(values.slice(0, -1)); // Exclude current observation
254
- const sd = stdDev(values.slice(0, -1));
255
-
256
- if (isAnomaly(check.value, m, sd, this.anomalyThreshold)) {
257
- const zScore = sd > 0 ? Math.round(((check.value - m) / sd) * 100) / 100 : 0;
258
- anomalies.push({
259
- metric: check.metric,
260
- label: check.label,
261
- value: check.value,
262
- expected: { mean: Math.round(m * 100) / 100, stdDev: Math.round(sd * 100) / 100 },
263
- zScore,
264
- direction: check.value > m ? 'above' : 'below'
265
- });
266
- }
267
- }
268
-
269
- return anomalies;
270
- }
271
-
272
- /** @private */
273
- _calculateRiskLevel() {
274
- if (this._totalObservations < this.learningPeriod) return 'unknown';
275
-
276
- const recentAnomalies = this._anomalies.filter(a => Date.now() - a.timestamp < 600000);
277
- if (recentAnomalies.length > 10) return 'critical';
278
- if (recentAnomalies.length > 5) return 'high';
279
- if (recentAnomalies.length > 2) return 'medium';
280
- if (recentAnomalies.length > 0) return 'low';
281
- return 'normal';
282
- }
283
- }
284
-
285
- // =========================================================================
286
- // EXPORTS
287
- // =========================================================================
288
-
289
- module.exports = { BehaviorProfile, mean, stdDev, isAnomaly };
1
+ 'use strict';
2
+
3
+ /**
4
+ * Agent Shield — Agent Behavior Profiling (v3.0)
5
+ *
6
+ * Establishes baselines for normal agent behavior and detects anomalies
7
+ * that may indicate compromise, drift, or attack influence.
8
+ *
9
+ * Tracks: response patterns, tool usage, topic distribution, timing,
10
+ * output length, sentiment shifts, and more.
11
+ *
12
+ * All processing runs locally — no data ever leaves your environment.
13
+ */
14
+
15
+ // =========================================================================
16
+ // STATISTICAL HELPERS
17
+ // =========================================================================
18
+
19
+ /**
20
+ * Calculate mean of an array.
21
+ * @param {number[]} arr
22
+ * @returns {number}
23
+ */
24
+ function mean(arr) {
25
+ return arr.length > 0 ? arr.reduce((a, b) => a + b, 0) / arr.length : 0;
26
+ }
27
+
28
+ /**
29
+ * Calculate standard deviation.
30
+ * @param {number[]} arr
31
+ * @returns {number}
32
+ */
33
+ function stdDev(arr) {
34
+ if (arr.length < 2) return 0;
35
+ const m = mean(arr);
36
+ const squaredDiffs = arr.map(x => (x - m) ** 2);
37
+ return Math.sqrt(squaredDiffs.reduce((a, b) => a + b, 0) / (arr.length - 1));
38
+ }
39
+
40
+ /**
41
+ * Check if a value is anomalous (beyond N standard deviations from mean).
42
+ * @param {number} value
43
+ * @param {number} m - Mean.
44
+ * @param {number} sd - Standard deviation.
45
+ * @param {number} [threshold=2] - Number of standard deviations.
46
+ * @returns {boolean}
47
+ */
48
+ function isAnomaly(value, m, sd, threshold = 2) {
49
+ if (sd === 0) return value !== m;
50
+ return Math.abs(value - m) > threshold * sd;
51
+ }
52
+
53
+ // =========================================================================
54
+ // BEHAVIOR PROFILE
55
+ // =========================================================================
56
+
57
+ /**
58
+ * Maintains a statistical profile of agent behavior.
59
+ */
60
+ class BehaviorProfile {
61
+ /**
62
+ * @param {object} [options]
63
+ * @param {number} [options.windowSize=200] - Number of observations to maintain.
64
+ * @param {number} [options.learningPeriod=20] - Observations before anomaly detection activates.
65
+ * @param {number} [options.anomalyThreshold=2.5] - Standard deviations for anomaly detection.
66
+ */
67
+ constructor(options = {}) {
68
+ this.windowSize = options.windowSize || 200;
69
+ this.learningPeriod = options.learningPeriod || 20;
70
+ this.anomalyThreshold = options.anomalyThreshold || 2.5;
71
+
72
+ this._metrics = {
73
+ responseLength: [],
74
+ responseTime: [],
75
+ toolCallCount: [],
76
+ threatScore: [],
77
+ topicEntropy: []
78
+ };
79
+
80
+ this._toolUsage = {};
81
+ this._topicDistribution = {};
82
+ this._totalObservations = 0;
83
+ this._anomalies = [];
84
+
85
+ console.log('[Agent Shield] BehaviorProfile initialized (windowSize: %d, learningPeriod: %d)', this.windowSize, this.learningPeriod);
86
+ }
87
+
88
+ /**
89
+ * Record an observation of agent behavior.
90
+ *
91
+ * @param {object} observation
92
+ * @param {number} [observation.responseLength] - Length of agent response.
93
+ * @param {number} [observation.responseTimeMs] - Time taken to respond.
94
+ * @param {string[]} [observation.toolsCalled] - Tools used in this turn.
95
+ * @param {number} [observation.threatScore] - Threat score from scanning.
96
+ * @param {string} [observation.topic] - Detected topic/category.
97
+ * @returns {object} { anomalies: Array, isLearning: boolean }
98
+ */
99
+ record(observation) {
100
+ this._totalObservations++;
101
+
102
+ // Record metrics
103
+ if (observation.responseLength !== undefined) {
104
+ this._addMetric('responseLength', observation.responseLength);
105
+ }
106
+ if (observation.responseTimeMs !== undefined) {
107
+ this._addMetric('responseTime', observation.responseTimeMs);
108
+ }
109
+ if (observation.toolsCalled) {
110
+ this._addMetric('toolCallCount', observation.toolsCalled.length);
111
+ for (const tool of observation.toolsCalled) {
112
+ this._toolUsage[tool] = (this._toolUsage[tool] || 0) + 1;
113
+ }
114
+ }
115
+ if (observation.threatScore !== undefined) {
116
+ this._addMetric('threatScore', observation.threatScore);
117
+ }
118
+ if (observation.topic) {
119
+ this._topicDistribution[observation.topic] = (this._topicDistribution[observation.topic] || 0) + 1;
120
+ }
121
+
122
+ // Check for anomalies (only after learning period)
123
+ const isLearning = this._totalObservations < this.learningPeriod;
124
+ const anomalies = isLearning ? [] : this._detectAnomalies(observation);
125
+
126
+ if (anomalies.length > 0) {
127
+ this._anomalies.push({
128
+ timestamp: Date.now(),
129
+ observation: this._totalObservations,
130
+ anomalies
131
+ });
132
+ // Prevent unbounded growth of anomaly history
133
+ if (this._anomalies.length > this.windowSize * 5) {
134
+ this._anomalies = this._anomalies.slice(-this.windowSize * 2);
135
+ }
136
+ }
137
+
138
+ return { anomalies, isLearning };
139
+ }
140
+
141
+ /**
142
+ * Get the current behavior baseline.
143
+ * @returns {object}
144
+ */
145
+ getBaseline() {
146
+ const baseline = {};
147
+ for (const [metric, values] of Object.entries(this._metrics)) {
148
+ if (values.length > 0) {
149
+ let min = values[0];
150
+ let max = values[0];
151
+ for (let i = 1; i < values.length; i++) {
152
+ if (values[i] < min) min = values[i];
153
+ if (values[i] > max) max = values[i];
154
+ }
155
+ baseline[metric] = {
156
+ mean: Math.round(mean(values) * 100) / 100,
157
+ stdDev: Math.round(stdDev(values) * 100) / 100,
158
+ min,
159
+ max,
160
+ samples: values.length
161
+ };
162
+ }
163
+ }
164
+ return baseline;
165
+ }
166
+
167
+ /**
168
+ * Get a full behavior report.
169
+ * @returns {object}
170
+ */
171
+ getReport() {
172
+ return {
173
+ totalObservations: this._totalObservations,
174
+ isLearning: this._totalObservations < this.learningPeriod,
175
+ baseline: this.getBaseline(),
176
+ toolUsage: { ...this._toolUsage },
177
+ topicDistribution: { ...this._topicDistribution },
178
+ anomalyCount: this._anomalies.length,
179
+ recentAnomalies: this._anomalies.slice(-10),
180
+ riskLevel: this._calculateRiskLevel()
181
+ };
182
+ }
183
+
184
+ /**
185
+ * Check if the agent appears to be behaving normally.
186
+ * @returns {object} { normal: boolean, riskLevel, concerns: string[] }
187
+ */
188
+ healthCheck() {
189
+ const concerns = [];
190
+ const report = this.getReport();
191
+
192
+ if (report.isLearning) {
193
+ return { normal: true, riskLevel: 'unknown', concerns: ['Still in learning period.'] };
194
+ }
195
+
196
+ // Check for sudden tool usage changes
197
+ const totalToolCalls = Object.values(this._toolUsage).reduce((a, b) => a + b, 0);
198
+ if (totalToolCalls > 0) {
199
+ for (const [tool, count] of Object.entries(this._toolUsage)) {
200
+ const ratio = count / totalToolCalls;
201
+ if (ratio > 0.7 && totalToolCalls > 10) {
202
+ concerns.push(`Tool "${tool}" dominates usage at ${(ratio * 100).toFixed(0)}%.`);
203
+ }
204
+ }
205
+ }
206
+
207
+ // Check for high threat score trend
208
+ const recentThreats = this._metrics.threatScore.slice(-20);
209
+ if (recentThreats.length >= 5 && mean(recentThreats) > 0.5) {
210
+ concerns.push('Recent threat scores are elevated.');
211
+ }
212
+
213
+ // Check for anomaly frequency
214
+ const recentAnomalies = this._anomalies.filter(a => Date.now() - a.timestamp < 300000);
215
+ if (recentAnomalies.length > 5) {
216
+ concerns.push(`${recentAnomalies.length} anomalies in the last 5 minutes.`);
217
+ }
218
+
219
+ return {
220
+ normal: concerns.length === 0,
221
+ riskLevel: report.riskLevel,
222
+ concerns
223
+ };
224
+ }
225
+
226
+ /** Reset the profile. */
227
+ reset() {
228
+ for (const key of Object.keys(this._metrics)) {
229
+ this._metrics[key] = [];
230
+ }
231
+ this._toolUsage = {};
232
+ this._topicDistribution = {};
233
+ this._totalObservations = 0;
234
+ this._anomalies = [];
235
+ }
236
+
237
+ /** @private */
238
+ _addMetric(name, value) {
239
+ if (!this._metrics[name]) this._metrics[name] = [];
240
+ this._metrics[name].push(value);
241
+ if (this._metrics[name].length > this.windowSize) {
242
+ this._metrics[name].shift();
243
+ }
244
+ }
245
+
246
+ /** @private */
247
+ _detectAnomalies(observation) {
248
+ const anomalies = [];
249
+
250
+ const checks = [
251
+ { metric: 'responseLength', value: observation.responseLength, label: 'Response length' },
252
+ { metric: 'responseTime', value: observation.responseTimeMs, label: 'Response time' },
253
+ { metric: 'toolCallCount', value: observation.toolsCalled ? observation.toolsCalled.length : undefined, label: 'Tool call count' },
254
+ { metric: 'threatScore', value: observation.threatScore, label: 'Threat score' }
255
+ ];
256
+
257
+ for (const check of checks) {
258
+ if (check.value === undefined) continue;
259
+
260
+ const values = this._metrics[check.metric];
261
+ if (values.length < this.learningPeriod) continue;
262
+
263
+ const m = mean(values.slice(0, -1)); // Exclude current observation
264
+ const sd = stdDev(values.slice(0, -1));
265
+
266
+ if (isAnomaly(check.value, m, sd, this.anomalyThreshold)) {
267
+ const zScore = sd > 0 ? Math.round(((check.value - m) / sd) * 100) / 100 : 0;
268
+ anomalies.push({
269
+ metric: check.metric,
270
+ label: check.label,
271
+ value: check.value,
272
+ expected: { mean: Math.round(m * 100) / 100, stdDev: Math.round(sd * 100) / 100 },
273
+ zScore,
274
+ direction: check.value > m ? 'above' : 'below'
275
+ });
276
+ }
277
+ }
278
+
279
+ return anomalies;
280
+ }
281
+
282
+ /** @private */
283
+ _calculateRiskLevel() {
284
+ if (this._totalObservations < this.learningPeriod) return 'unknown';
285
+
286
+ const recentAnomalies = this._anomalies.filter(a => Date.now() - a.timestamp < 600000);
287
+ if (recentAnomalies.length > 10) return 'critical';
288
+ if (recentAnomalies.length > 5) return 'high';
289
+ if (recentAnomalies.length > 2) return 'medium';
290
+ if (recentAnomalies.length > 0) return 'low';
291
+ return 'normal';
292
+ }
293
+ }
294
+
295
+ // =========================================================================
296
+ // EXPORTS
297
+ // =========================================================================
298
+
299
+ module.exports = { BehaviorProfile, mean, stdDev, isAnomaly };
@@ -160,11 +160,8 @@ class BehavioralDNA {
160
160
  this._createdAt = Date.now();
161
161
  this._lastObservation = null;
162
162
 
163
- console.log(
164
- '[Agent Shield] BehavioralDNA initialized (learningPeriod: %d, threshold: %s)',
165
- this.learningPeriod,
166
- this.anomalyThreshold
167
- );
163
+ console.log('[Agent Shield] BehavioralDNA initialized (learningPeriod: %d, threshold: %s)',
164
+ this.learningPeriod, this.anomalyThreshold);
168
165
  }
169
166
 
170
167
  /**
@@ -481,10 +478,8 @@ class BehavioralDNA {
481
478
 
482
479
  this._toolDistribution = data.toolDistribution ? { ...data.toolDistribution } : {};
483
480
 
484
- console.log(
485
- '[Agent Shield] BehavioralDNA fingerprint loaded (%d observations)',
486
- this._observationCount
487
- );
481
+ console.log('[Agent Shield] BehavioralDNA fingerprint loaded (%d observations)',
482
+ this._observationCount);
488
483
  }
489
484
 
490
485
  /**