@wardnmesh/sdk-node 0.4.1 → 0.4.7
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/CHANGELOG.md +147 -0
- package/README.md +3 -3
- package/package.json +12 -5
- package/dist/agent-guard.d.ts +0 -28
- package/dist/agent-guard.js +0 -206
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to @wardnmesh/sdk-node will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.4.0] - 2026-01-17
|
|
9
|
+
|
|
10
|
+
### 🚨 Breaking Changes
|
|
11
|
+
|
|
12
|
+
**Action-Based Architecture**: Replaces boolean `allowed` field with granular action types.
|
|
13
|
+
|
|
14
|
+
- **`ScanResult.allowed` → `ScanResult.action`**
|
|
15
|
+
- Type: `boolean` → `ThreatAction` (`'block'` | `'confirm'` | `'warn'` | `'log'` | `'allow'`)
|
|
16
|
+
- Provides fine-grained control over threat response
|
|
17
|
+
- Enables user confirmation for high-risk operations
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **Confirmation Support** (`action: 'confirm'`)
|
|
22
|
+
- New `confirmationDetails` field in `ScanResult`
|
|
23
|
+
- Pre-formatted confirmation messages with context
|
|
24
|
+
- Configurable timeout and default action
|
|
25
|
+
- Designed for user approval dialogs in CLI/UI
|
|
26
|
+
|
|
27
|
+
- **Action Priority System**
|
|
28
|
+
- `determineAction()` method with priority: `block` > `confirm` > `warn` > `log` > `allow`
|
|
29
|
+
- Defensive fail-closed design: defaults to `'block'` on invalid actions
|
|
30
|
+
- Comprehensive validation with fallback safety
|
|
31
|
+
|
|
32
|
+
- **Enhanced Violation Metadata**
|
|
33
|
+
- Added `recommendedAction: ThreatAction` field to `Violation`
|
|
34
|
+
- Added `scope: string` field for categorization
|
|
35
|
+
- Richer context for decision-making
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- **Core API**: `scan()` now returns `action` instead of `allowed`
|
|
40
|
+
- **Middleware**: Callbacks now receive full `ScanResult` instead of just `violations`
|
|
41
|
+
- **Error Handling**: Invalid `recommendedAction` values trigger warnings and fail-closed
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- **Defensive Design**: Prevents security bypass from missing/invalid `recommendedAction`
|
|
46
|
+
- **Type Safety**: All violation fields properly validated before action determination
|
|
47
|
+
|
|
48
|
+
### Migration
|
|
49
|
+
|
|
50
|
+
See [MIGRATION_v0.4.0.md](MIGRATION_v0.4.0.md) for detailed upgrade guide.
|
|
51
|
+
|
|
52
|
+
**Quick Migration**:
|
|
53
|
+
```typescript
|
|
54
|
+
// Before (v0.2.3)
|
|
55
|
+
if (!result.allowed) { throw new Error('Blocked'); }
|
|
56
|
+
|
|
57
|
+
// After (v0.4.0)
|
|
58
|
+
if (result.action === 'block') { throw new Error('Blocked'); }
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Testing
|
|
62
|
+
|
|
63
|
+
- ✅ 17 tests passing (4 test suites)
|
|
64
|
+
- ✅ All action types validated
|
|
65
|
+
- ✅ Confirmation flow tested
|
|
66
|
+
- ✅ Fail-closed behavior verified
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## [0.2.3] - 2026-01-16
|
|
71
|
+
|
|
72
|
+
### Fixed
|
|
73
|
+
|
|
74
|
+
- Improved severity-to-action mapping in integrations
|
|
75
|
+
- Enhanced error handling with better null checks
|
|
76
|
+
|
|
77
|
+
### Documentation
|
|
78
|
+
|
|
79
|
+
- Updated examples with current API patterns
|
|
80
|
+
- Clarified rule configuration options
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## [0.2.0] - 2026-01-15
|
|
85
|
+
|
|
86
|
+
### Added
|
|
87
|
+
|
|
88
|
+
- **Semantic Analysis**: ML-based threat detection using local models
|
|
89
|
+
- **State Tracking**: Session-aware detection for multi-turn attacks
|
|
90
|
+
- **Pattern Detectors**: Regex-based threat pattern matching
|
|
91
|
+
- **Sequence Detectors**: Multi-step attack pattern recognition
|
|
92
|
+
|
|
93
|
+
### Changed
|
|
94
|
+
|
|
95
|
+
- Unified detector API for all detection types
|
|
96
|
+
- Improved telemetry with detailed metrics
|
|
97
|
+
|
|
98
|
+
### Performance
|
|
99
|
+
|
|
100
|
+
- <20ms latency for most scans
|
|
101
|
+
- Local-first processing (no external API calls)
|
|
102
|
+
- Lazy loading for ML models
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## [0.1.0] - 2026-01-10
|
|
107
|
+
|
|
108
|
+
### Added
|
|
109
|
+
|
|
110
|
+
- Initial release of WardnMesh SDK for Node.js
|
|
111
|
+
- Core `Wardn` class with singleton pattern
|
|
112
|
+
- Basic threat detection for:
|
|
113
|
+
- PII (Personal Identifiable Information)
|
|
114
|
+
- Prompt injection patterns
|
|
115
|
+
- API key leakage
|
|
116
|
+
- Express middleware support
|
|
117
|
+
- Next.js middleware support
|
|
118
|
+
- Vercel AI SDK integration
|
|
119
|
+
- Local rule management
|
|
120
|
+
|
|
121
|
+
### Features
|
|
122
|
+
|
|
123
|
+
- Rule-based scanning engine
|
|
124
|
+
- Configurable severity levels
|
|
125
|
+
- Telemetry and reporting
|
|
126
|
+
- Extensible detector system
|
|
127
|
+
- TypeScript support with full type definitions
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Version Compatibility
|
|
132
|
+
|
|
133
|
+
| SDK Version | MCP Server | Node.js | Status |
|
|
134
|
+
|-------------|------------|---------|--------|
|
|
135
|
+
| 0.4.0 | 0.2.3+ | 18+ | ✅ Current |
|
|
136
|
+
| 0.2.3 | 0.2.0+ | 18+ | ⚠️ Legacy |
|
|
137
|
+
| 0.2.0 | 0.2.0+ | 18+ | ⚠️ Legacy |
|
|
138
|
+
| 0.1.0 | 0.1.0+ | 18+ | ❌ Deprecated |
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Links
|
|
143
|
+
|
|
144
|
+
- [NPM Package](https://www.npmjs.com/package/@wardnmesh/sdk-node)
|
|
145
|
+
- [GitHub Repository](https://github.com/PCIRCLE-AI/wardnmesh)
|
|
146
|
+
- [Documentation](https://wardnmesh.ai/docs/sdk)
|
|
147
|
+
- [Migration Guides](MIGRATION_v0.4.0.md)
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @wardnmesh/sdk-node
|
|
2
2
|
|
|
3
|
-
> **Latest Version: v0.4.
|
|
3
|
+
> **Latest Version: v0.4.5** (Released 2026-01-19)
|
|
4
4
|
|
|
5
5
|
**WardnMesh.AI** (formerly AgentGuard) is an active defense middleware for AI Agents. This SDK allows you to verify LLM inputs/outputs, block prompt injections, and prevent data exfiltration in real-time.
|
|
6
6
|
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
## Installation
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
npm install @wardnmesh/sdk-node@
|
|
29
|
+
npm install @wardnmesh/sdk-node@latest
|
|
30
30
|
# or
|
|
31
|
-
yarn add @wardnmesh/sdk-node@
|
|
31
|
+
yarn add @wardnmesh/sdk-node@latest
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
## v0.4.0 API Overview
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wardnmesh/sdk-node",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.7",
|
|
4
4
|
"description": "WardnMesh.AI Node.js SDK - Active Defense Middleware for AI Agents",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -20,16 +20,18 @@
|
|
|
20
20
|
},
|
|
21
21
|
"scripts": {
|
|
22
22
|
"build": "tsc",
|
|
23
|
+
"prepack": "npm run build",
|
|
23
24
|
"test": "jest"
|
|
24
25
|
},
|
|
25
26
|
"bin": {
|
|
26
|
-
"wardn-init": "
|
|
27
|
+
"wardn-init": "bin/setup.js"
|
|
27
28
|
},
|
|
28
29
|
"files": [
|
|
29
30
|
"dist",
|
|
30
31
|
"bin",
|
|
31
32
|
"README.md",
|
|
32
|
-
"LICENSE"
|
|
33
|
+
"LICENSE",
|
|
34
|
+
"CHANGELOG.md"
|
|
33
35
|
],
|
|
34
36
|
"publishConfig": {
|
|
35
37
|
"access": "public"
|
|
@@ -42,18 +44,23 @@
|
|
|
42
44
|
],
|
|
43
45
|
"repository": {
|
|
44
46
|
"type": "git",
|
|
45
|
-
"url": "git+https://github.com/PCIRCLE-AI/wardnmesh.git"
|
|
47
|
+
"url": "git+https://github.com/PCIRCLE-AI/wardnmesh-sdk-node.git"
|
|
46
48
|
},
|
|
47
49
|
"bugs": {
|
|
48
|
-
"url": "https://github.com/PCIRCLE-AI/wardnmesh/issues"
|
|
50
|
+
"url": "https://github.com/PCIRCLE-AI/wardnmesh-sdk-node/issues"
|
|
49
51
|
},
|
|
50
52
|
"homepage": "https://wardnmesh.ai",
|
|
51
53
|
"author": "KT",
|
|
52
54
|
"license": "Elastic-2.0",
|
|
55
|
+
"engines": {
|
|
56
|
+
"node": ">=18.0.0",
|
|
57
|
+
"npm": ">=9.0.0"
|
|
58
|
+
},
|
|
53
59
|
"devDependencies": {
|
|
54
60
|
"@types/jest": "^29.5.11",
|
|
55
61
|
"@types/node": "^20.10.0",
|
|
56
62
|
"jest": "^29.7.0",
|
|
63
|
+
"next": "^14.2.35",
|
|
57
64
|
"ts-jest": "^29.1.1",
|
|
58
65
|
"typescript": "^5.0.0"
|
|
59
66
|
},
|
package/dist/agent-guard.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { AgentGuardConfig, ScanResult, AgentRequest } from "./types";
|
|
2
|
-
import { SessionStateProvider } from "./state/session-manager";
|
|
3
|
-
export declare class AgentGuard {
|
|
4
|
-
private static instance;
|
|
5
|
-
private config;
|
|
6
|
-
private stateProvider;
|
|
7
|
-
private telemetry;
|
|
8
|
-
private patternDetector;
|
|
9
|
-
private sequenceDetector;
|
|
10
|
-
private stateDetector;
|
|
11
|
-
private semanticDetector;
|
|
12
|
-
private constructor();
|
|
13
|
-
private initTelemetry;
|
|
14
|
-
static getInstance(): AgentGuard;
|
|
15
|
-
static init(config: AgentGuardConfig, stateProvider?: SessionStateProvider): AgentGuard;
|
|
16
|
-
/** Main entry point to scan an agent request */
|
|
17
|
-
scan(request: AgentRequest): Promise<ScanResult>;
|
|
18
|
-
/** Normalize request to ToolData format */
|
|
19
|
-
private normalizeRequest;
|
|
20
|
-
/** Run detector for a single rule */
|
|
21
|
-
private detectViolation;
|
|
22
|
-
/** Handle semantic detection */
|
|
23
|
-
private detectSemanticViolation;
|
|
24
|
-
/** Report violation to telemetry */
|
|
25
|
-
private reportViolation;
|
|
26
|
-
/** Report scan completion to telemetry */
|
|
27
|
-
private reportScanComplete;
|
|
28
|
-
}
|
package/dist/agent-guard.js
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AgentGuard = void 0;
|
|
4
|
-
const pattern_1 = require("./detectors/pattern");
|
|
5
|
-
const sequence_1 = require("./detectors/sequence");
|
|
6
|
-
const state_1 = require("./detectors/state");
|
|
7
|
-
const session_manager_1 = require("./state/session-manager");
|
|
8
|
-
const reporter_1 = require("./telemetry/reporter");
|
|
9
|
-
const semantic_detector_1 = require("./detectors/semantic-detector");
|
|
10
|
-
/** Synchronous state adapter for in-request state management */
|
|
11
|
-
class SyncStateAdapter {
|
|
12
|
-
constructor(initialState, maxHistory = 50) {
|
|
13
|
-
this.maxHistory = maxHistory;
|
|
14
|
-
this.state = {
|
|
15
|
-
startTime: initialState.startTime || new Date().toISOString(),
|
|
16
|
-
toolCalls: initialState.toolCalls || [],
|
|
17
|
-
recentTools: initialState.recentTools || [],
|
|
18
|
-
detectedViolations: initialState.detectedViolations || [],
|
|
19
|
-
customState: initialState.customState || {},
|
|
20
|
-
currentFile: initialState.currentFile,
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
getRecentTools(count) {
|
|
24
|
-
const tools = this.state.recentTools || [];
|
|
25
|
-
return count ? tools.slice(-count) : tools;
|
|
26
|
-
}
|
|
27
|
-
setCustomState(key, value) {
|
|
28
|
-
this.state.customState[key] = value;
|
|
29
|
-
}
|
|
30
|
-
getCustomState(key) {
|
|
31
|
-
return this.state.customState[key];
|
|
32
|
-
}
|
|
33
|
-
addToolCall(tool) {
|
|
34
|
-
if (!this.state.recentTools)
|
|
35
|
-
this.state.recentTools = [];
|
|
36
|
-
this.state.recentTools.push(tool);
|
|
37
|
-
if (this.state.recentTools.length > this.maxHistory) {
|
|
38
|
-
this.state.recentTools.shift();
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
exportState() {
|
|
42
|
-
return this.state;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
class AgentGuard {
|
|
46
|
-
constructor(config, stateProvider) {
|
|
47
|
-
this.config = config;
|
|
48
|
-
this.stateProvider = stateProvider || new session_manager_1.InMemorySessionStateProvider();
|
|
49
|
-
this.telemetry = this.initTelemetry();
|
|
50
|
-
this.patternDetector = new pattern_1.PatternDetector();
|
|
51
|
-
this.sequenceDetector = new sequence_1.SequenceDetector();
|
|
52
|
-
this.stateDetector = new state_1.StateDetector();
|
|
53
|
-
this.semanticDetector = semantic_detector_1.SemanticDetector.getInstance();
|
|
54
|
-
// Emit startup event
|
|
55
|
-
this.telemetry.emit({
|
|
56
|
-
eventType: "agent_started",
|
|
57
|
-
timestamp: new Date().toISOString(),
|
|
58
|
-
data: {
|
|
59
|
-
config: {
|
|
60
|
-
appName: this.config.telemetry?.serviceName,
|
|
61
|
-
ruleCount: this.config.rules.length,
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
initTelemetry() {
|
|
67
|
-
if (this.config.telemetry?.enabled && process.env.CCB_ENDPOINT) {
|
|
68
|
-
return new reporter_1.CCBReporter(process.env.CCB_ENDPOINT, process.env.CCB_API_KEY || "", this.config.telemetry.serviceName || "unknown-service");
|
|
69
|
-
}
|
|
70
|
-
return new reporter_1.ConsoleReporter();
|
|
71
|
-
}
|
|
72
|
-
static getInstance() {
|
|
73
|
-
if (!AgentGuard.instance) {
|
|
74
|
-
throw new Error("AgentGuard not initialized. Call AgentGuard.init() first.");
|
|
75
|
-
}
|
|
76
|
-
return AgentGuard.instance;
|
|
77
|
-
}
|
|
78
|
-
static init(config, stateProvider) {
|
|
79
|
-
AgentGuard.instance = new AgentGuard(config, stateProvider);
|
|
80
|
-
return AgentGuard.instance;
|
|
81
|
-
}
|
|
82
|
-
/** Main entry point to scan an agent request */
|
|
83
|
-
async scan(request) {
|
|
84
|
-
const start = Date.now();
|
|
85
|
-
const violations = [];
|
|
86
|
-
const sessionId = request.sessionId || "default";
|
|
87
|
-
try {
|
|
88
|
-
const rawState = await this.stateProvider.getState(sessionId);
|
|
89
|
-
const stateAdapter = new SyncStateAdapter(rawState, this.config.maxHistorySize);
|
|
90
|
-
const toolData = this.normalizeRequest(request);
|
|
91
|
-
stateAdapter.addToolCall(toolData);
|
|
92
|
-
// Lazy load semantic model if needed
|
|
93
|
-
if (this.config.rules.some((r) => r.detector.type === "semantic")) {
|
|
94
|
-
await this.semanticDetector.init();
|
|
95
|
-
}
|
|
96
|
-
// Run all detectors
|
|
97
|
-
for (const rule of this.config.rules) {
|
|
98
|
-
const violation = await this.detectViolation(rule, toolData, stateAdapter);
|
|
99
|
-
if (violation) {
|
|
100
|
-
violations.push(violation);
|
|
101
|
-
this.reportViolation(violation, toolData, sessionId);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
await this.stateProvider.setState(sessionId, stateAdapter.exportState());
|
|
105
|
-
const result = {
|
|
106
|
-
allowed: !violations.some((v) => v.severity === "critical"),
|
|
107
|
-
violations,
|
|
108
|
-
latencyMs: Date.now() - start,
|
|
109
|
-
metadata: { analyzedRules: this.config.rules.length },
|
|
110
|
-
};
|
|
111
|
-
this.reportScanComplete(result, sessionId);
|
|
112
|
-
return result;
|
|
113
|
-
}
|
|
114
|
-
catch (error) {
|
|
115
|
-
// Fail-Open Resilience: Never crash the application
|
|
116
|
-
console.error("[AgentGuard] Scan failed, failing open:", error);
|
|
117
|
-
this.telemetry.emit({
|
|
118
|
-
eventType: "error",
|
|
119
|
-
timestamp: new Date().toISOString(),
|
|
120
|
-
data: {
|
|
121
|
-
error: error instanceof Error ? error.message : "Unknown error",
|
|
122
|
-
sessionId,
|
|
123
|
-
},
|
|
124
|
-
});
|
|
125
|
-
return {
|
|
126
|
-
allowed: true, // Fail-open
|
|
127
|
-
violations: [],
|
|
128
|
-
latencyMs: Date.now() - start,
|
|
129
|
-
metadata: {
|
|
130
|
-
error: true,
|
|
131
|
-
errorDetails: error instanceof Error ? error.message : "Unknown",
|
|
132
|
-
},
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
/** Normalize request to ToolData format */
|
|
137
|
-
normalizeRequest(request) {
|
|
138
|
-
return {
|
|
139
|
-
toolName: request.toolName || "llm_input",
|
|
140
|
-
parameters: request.parameters || { prompt: request.prompt || "" },
|
|
141
|
-
result: { success: true },
|
|
142
|
-
duration: 0,
|
|
143
|
-
timestamp: new Date().toISOString(),
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
/** Run detector for a single rule */
|
|
147
|
-
async detectViolation(rule, toolData, stateAdapter) {
|
|
148
|
-
switch (rule.detector.type) {
|
|
149
|
-
case "pattern":
|
|
150
|
-
return this.patternDetector.detect(toolData, rule, stateAdapter);
|
|
151
|
-
case "sequence":
|
|
152
|
-
return this.sequenceDetector.detect(toolData, rule, stateAdapter);
|
|
153
|
-
case "state":
|
|
154
|
-
return this.stateDetector.detect(toolData, rule, stateAdapter);
|
|
155
|
-
case "semantic":
|
|
156
|
-
return this.detectSemanticViolation(rule, toolData);
|
|
157
|
-
default:
|
|
158
|
-
return null;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
/** Handle semantic detection */
|
|
162
|
-
async detectSemanticViolation(rule, toolData) {
|
|
163
|
-
const prompt = toolData.parameters.prompt ||
|
|
164
|
-
JSON.stringify(toolData.parameters);
|
|
165
|
-
const config = rule.detector.config;
|
|
166
|
-
const { detected, reason, score } = await this.semanticDetector.scan(prompt, config.threshold || 0.75);
|
|
167
|
-
if (!detected)
|
|
168
|
-
return null;
|
|
169
|
-
return {
|
|
170
|
-
id: crypto.randomUUID(),
|
|
171
|
-
ruleId: rule.id,
|
|
172
|
-
ruleName: rule.name,
|
|
173
|
-
severity: rule.severity,
|
|
174
|
-
description: reason || "Semantic Violation",
|
|
175
|
-
context: {
|
|
176
|
-
toolName: toolData.toolName,
|
|
177
|
-
toolData,
|
|
178
|
-
additionalInfo: { score },
|
|
179
|
-
},
|
|
180
|
-
timestamp: new Date().toISOString(),
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
/** Report violation to telemetry */
|
|
184
|
-
reportViolation(violation, toolData, sessionId) {
|
|
185
|
-
this.telemetry.emit({
|
|
186
|
-
eventType: "violation_detected",
|
|
187
|
-
timestamp: new Date().toISOString(),
|
|
188
|
-
data: { violation, toolData },
|
|
189
|
-
metadata: { sessionId },
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
/** Report scan completion to telemetry */
|
|
193
|
-
reportScanComplete(result, sessionId) {
|
|
194
|
-
this.telemetry.emit({
|
|
195
|
-
eventType: "scan_complete",
|
|
196
|
-
timestamp: new Date().toISOString(),
|
|
197
|
-
data: {
|
|
198
|
-
allowed: result.allowed,
|
|
199
|
-
latencyMs: result.latencyMs,
|
|
200
|
-
violationCount: result.violations.length,
|
|
201
|
-
},
|
|
202
|
-
metadata: { sessionId },
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
exports.AgentGuard = AgentGuard;
|