@juspay/neurolink 7.38.1 → 7.39.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.
- package/CHANGELOG.md +6 -0
- package/dist/hitl/hitlErrors.d.ts +38 -0
- package/dist/hitl/hitlErrors.js +54 -0
- package/dist/hitl/hitlManager.d.ts +100 -0
- package/dist/hitl/hitlManager.js +457 -0
- package/dist/hitl/index.d.ts +8 -0
- package/dist/hitl/index.js +9 -0
- package/dist/hitl/types.d.ts +196 -0
- package/dist/hitl/types.js +8 -0
- package/dist/lib/hitl/hitlErrors.d.ts +38 -0
- package/dist/lib/hitl/hitlErrors.js +54 -0
- package/dist/lib/hitl/hitlManager.d.ts +100 -0
- package/dist/lib/hitl/hitlManager.js +457 -0
- package/dist/lib/hitl/index.d.ts +8 -0
- package/dist/lib/hitl/index.js +9 -0
- package/dist/lib/hitl/types.d.ts +196 -0
- package/dist/lib/hitl/types.js +8 -0
- package/dist/lib/mcp/externalServerManager.d.ts +11 -0
- package/dist/lib/mcp/externalServerManager.js +69 -2
- package/dist/lib/mcp/toolRegistry.d.ts +11 -0
- package/dist/lib/mcp/toolRegistry.js +69 -3
- package/dist/lib/neurolink.d.ts +27 -0
- package/dist/lib/neurolink.js +146 -0
- package/dist/mcp/externalServerManager.d.ts +11 -0
- package/dist/mcp/externalServerManager.js +69 -2
- package/dist/mcp/toolRegistry.d.ts +11 -0
- package/dist/mcp/toolRegistry.js +69 -3
- package/dist/neurolink.d.ts +27 -0
- package/dist/neurolink.js +146 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## [7.39.0](https://github.com/juspay/neurolink/compare/v7.38.1...v7.39.0) (2025-09-16)
|
2
|
+
|
3
|
+
### Features
|
4
|
+
|
5
|
+
- **(hitl):** Implemented human in the loop for sdk ([1a66f53](https://github.com/juspay/neurolink/commit/1a66f533d4d92fb33d203947a4c6648a72db631c))
|
6
|
+
|
1
7
|
## [7.38.1](https://github.com/juspay/neurolink/compare/v7.38.0...v7.38.1) (2025-09-16)
|
2
8
|
|
3
9
|
### Bug Fixes
|
@@ -0,0 +1,38 @@
|
|
1
|
+
/**
|
2
|
+
* HITL (Human-in-the-Loop) Error Classes
|
3
|
+
*
|
4
|
+
* Provides structured error handling for HITL safety mechanisms.
|
5
|
+
* These errors allow applications to distinguish between different
|
6
|
+
* types of HITL failures and handle them appropriately.
|
7
|
+
*/
|
8
|
+
/**
|
9
|
+
* Base class for all HITL-related errors
|
10
|
+
*/
|
11
|
+
export declare class HITLError extends Error {
|
12
|
+
readonly confirmationId?: string | undefined;
|
13
|
+
constructor(message: string, confirmationId?: string | undefined);
|
14
|
+
}
|
15
|
+
/**
|
16
|
+
* Thrown when a user explicitly rejects a tool execution request
|
17
|
+
* This indicates the HITL system worked correctly - the user saw the request
|
18
|
+
* and made a conscious decision to deny it.
|
19
|
+
*/
|
20
|
+
export declare class HITLUserRejectedError extends HITLError {
|
21
|
+
readonly toolName: string;
|
22
|
+
readonly reason?: string | undefined;
|
23
|
+
constructor(message: string, toolName: string, reason?: string | undefined, confirmationId?: string);
|
24
|
+
}
|
25
|
+
/**
|
26
|
+
* Thrown when a confirmation request times out without user response
|
27
|
+
* This indicates the user didn't respond within the configured timeout period.
|
28
|
+
*/
|
29
|
+
export declare class HITLTimeoutError extends HITLError {
|
30
|
+
readonly timeout: number;
|
31
|
+
constructor(message: string, confirmationId: string, timeout: number);
|
32
|
+
}
|
33
|
+
/**
|
34
|
+
* Thrown when HITL configuration is invalid or missing required properties
|
35
|
+
*/
|
36
|
+
export declare class HITLConfigurationError extends HITLError {
|
37
|
+
constructor(message: string);
|
38
|
+
}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
/**
|
2
|
+
* HITL (Human-in-the-Loop) Error Classes
|
3
|
+
*
|
4
|
+
* Provides structured error handling for HITL safety mechanisms.
|
5
|
+
* These errors allow applications to distinguish between different
|
6
|
+
* types of HITL failures and handle them appropriately.
|
7
|
+
*/
|
8
|
+
/**
|
9
|
+
* Base class for all HITL-related errors
|
10
|
+
*/
|
11
|
+
export class HITLError extends Error {
|
12
|
+
confirmationId;
|
13
|
+
constructor(message, confirmationId) {
|
14
|
+
super(message);
|
15
|
+
this.confirmationId = confirmationId;
|
16
|
+
this.name = "HITLError";
|
17
|
+
}
|
18
|
+
}
|
19
|
+
/**
|
20
|
+
* Thrown when a user explicitly rejects a tool execution request
|
21
|
+
* This indicates the HITL system worked correctly - the user saw the request
|
22
|
+
* and made a conscious decision to deny it.
|
23
|
+
*/
|
24
|
+
export class HITLUserRejectedError extends HITLError {
|
25
|
+
toolName;
|
26
|
+
reason;
|
27
|
+
constructor(message, toolName, reason, confirmationId) {
|
28
|
+
super(message, confirmationId);
|
29
|
+
this.toolName = toolName;
|
30
|
+
this.reason = reason;
|
31
|
+
this.name = "HITLUserRejectedError";
|
32
|
+
}
|
33
|
+
}
|
34
|
+
/**
|
35
|
+
* Thrown when a confirmation request times out without user response
|
36
|
+
* This indicates the user didn't respond within the configured timeout period.
|
37
|
+
*/
|
38
|
+
export class HITLTimeoutError extends HITLError {
|
39
|
+
timeout;
|
40
|
+
constructor(message, confirmationId, timeout) {
|
41
|
+
super(message, confirmationId);
|
42
|
+
this.timeout = timeout;
|
43
|
+
this.name = "HITLTimeoutError";
|
44
|
+
}
|
45
|
+
}
|
46
|
+
/**
|
47
|
+
* Thrown when HITL configuration is invalid or missing required properties
|
48
|
+
*/
|
49
|
+
export class HITLConfigurationError extends HITLError {
|
50
|
+
constructor(message) {
|
51
|
+
super(message);
|
52
|
+
this.name = "HITLConfigurationError";
|
53
|
+
}
|
54
|
+
}
|
@@ -0,0 +1,100 @@
|
|
1
|
+
/**
|
2
|
+
* HITL (Human-in-the-Loop) Manager
|
3
|
+
*
|
4
|
+
* Central orchestrator for all HITL confirmation workflows.
|
5
|
+
* Manages user confirmation requests, timeouts, and argument modifications
|
6
|
+
* for enterprise-grade AI safety.
|
7
|
+
*/
|
8
|
+
import { EventEmitter } from "events";
|
9
|
+
import type { HITLConfig, ConfirmationResult, HITLStatistics } from "./types.js";
|
10
|
+
/**
|
11
|
+
* HITLManager - Central orchestrator for Human-in-the-Loop safety mechanisms
|
12
|
+
*
|
13
|
+
* Features:
|
14
|
+
* - Real-time user confirmation via events
|
15
|
+
* - Configurable dangerous action detection
|
16
|
+
* - Custom rule engine for complex scenarios
|
17
|
+
* - Argument modification support
|
18
|
+
* - Comprehensive audit logging
|
19
|
+
* - Timeout handling with cleanup
|
20
|
+
*/
|
21
|
+
export declare class HITLManager extends EventEmitter {
|
22
|
+
private config;
|
23
|
+
private pendingConfirmations;
|
24
|
+
private statistics;
|
25
|
+
constructor(config: HITLConfig);
|
26
|
+
/**
|
27
|
+
* Validate HITL configuration and apply defaults
|
28
|
+
*/
|
29
|
+
private validateConfig;
|
30
|
+
/**
|
31
|
+
* Check if a tool requires confirmation based on configuration
|
32
|
+
*/
|
33
|
+
requiresConfirmation(toolName: string, args?: unknown): boolean;
|
34
|
+
/**
|
35
|
+
* Request confirmation for a tool execution
|
36
|
+
*/
|
37
|
+
requestConfirmation(toolName: string, arguments_: unknown, context?: {
|
38
|
+
serverId?: string;
|
39
|
+
sessionId?: string;
|
40
|
+
userId?: string;
|
41
|
+
}): Promise<ConfirmationResult>;
|
42
|
+
/**
|
43
|
+
* Process user response to confirmation request
|
44
|
+
*/
|
45
|
+
processUserResponse(confirmationId: string, response: {
|
46
|
+
approved: boolean;
|
47
|
+
reason?: string;
|
48
|
+
modifiedArguments?: unknown;
|
49
|
+
responseTime?: number;
|
50
|
+
userId?: string;
|
51
|
+
}): void;
|
52
|
+
/**
|
53
|
+
* Handle confirmation timeout
|
54
|
+
*/
|
55
|
+
private handleTimeout;
|
56
|
+
/**
|
57
|
+
* Set up event handlers for processing responses
|
58
|
+
*/
|
59
|
+
private setupEventHandlers;
|
60
|
+
/**
|
61
|
+
* Generate unique confirmation ID
|
62
|
+
*/
|
63
|
+
private generateConfirmationId;
|
64
|
+
/**
|
65
|
+
* Generate human-readable action description
|
66
|
+
*/
|
67
|
+
private generateActionDescription;
|
68
|
+
/**
|
69
|
+
* Get keywords that triggered HITL
|
70
|
+
*/
|
71
|
+
private getTriggeredKeywords;
|
72
|
+
/**
|
73
|
+
* Log audit events for compliance and debugging
|
74
|
+
*/
|
75
|
+
private logAuditEvent;
|
76
|
+
/**
|
77
|
+
* Get current HITL usage statistics
|
78
|
+
*/
|
79
|
+
getStatistics(): HITLStatistics;
|
80
|
+
/**
|
81
|
+
* Get current configuration
|
82
|
+
*/
|
83
|
+
getConfig(): HITLConfig;
|
84
|
+
/**
|
85
|
+
* Update configuration (for dynamic reconfiguration)
|
86
|
+
*/
|
87
|
+
updateConfig(newConfig: Partial<HITLConfig>): void;
|
88
|
+
/**
|
89
|
+
* Clean up resources and reject pending confirmations
|
90
|
+
*/
|
91
|
+
cleanup(): void;
|
92
|
+
/**
|
93
|
+
* Check if manager is currently enabled
|
94
|
+
*/
|
95
|
+
isEnabled(): boolean;
|
96
|
+
/**
|
97
|
+
* Get count of pending confirmations
|
98
|
+
*/
|
99
|
+
getPendingCount(): number;
|
100
|
+
}
|
@@ -0,0 +1,457 @@
|
|
1
|
+
/**
|
2
|
+
* HITL (Human-in-the-Loop) Manager
|
3
|
+
*
|
4
|
+
* Central orchestrator for all HITL confirmation workflows.
|
5
|
+
* Manages user confirmation requests, timeouts, and argument modifications
|
6
|
+
* for enterprise-grade AI safety.
|
7
|
+
*/
|
8
|
+
import { EventEmitter } from "events";
|
9
|
+
import { randomUUID } from "crypto";
|
10
|
+
import { HITLTimeoutError, HITLConfigurationError } from "./hitlErrors.js";
|
11
|
+
import { logger } from "../utils/logger.js";
|
12
|
+
/**
|
13
|
+
* HITLManager - Central orchestrator for Human-in-the-Loop safety mechanisms
|
14
|
+
*
|
15
|
+
* Features:
|
16
|
+
* - Real-time user confirmation via events
|
17
|
+
* - Configurable dangerous action detection
|
18
|
+
* - Custom rule engine for complex scenarios
|
19
|
+
* - Argument modification support
|
20
|
+
* - Comprehensive audit logging
|
21
|
+
* - Timeout handling with cleanup
|
22
|
+
*/
|
23
|
+
export class HITLManager extends EventEmitter {
|
24
|
+
config;
|
25
|
+
pendingConfirmations = new Map();
|
26
|
+
statistics = {
|
27
|
+
totalRequests: 0,
|
28
|
+
pendingRequests: 0,
|
29
|
+
averageResponseTime: 0,
|
30
|
+
approvedRequests: 0,
|
31
|
+
rejectedRequests: 0,
|
32
|
+
timedOutRequests: 0,
|
33
|
+
};
|
34
|
+
constructor(config) {
|
35
|
+
super();
|
36
|
+
this.config = this.validateConfig(config);
|
37
|
+
this.setupEventHandlers();
|
38
|
+
}
|
39
|
+
/**
|
40
|
+
* Validate HITL configuration and apply defaults
|
41
|
+
*/
|
42
|
+
validateConfig(config) {
|
43
|
+
// Apply defaults for optional fields
|
44
|
+
const configWithDefaults = {
|
45
|
+
enabled: config.enabled,
|
46
|
+
dangerousActions: config.dangerousActions,
|
47
|
+
timeout: config.timeout ?? 30000, // Default: 30 seconds
|
48
|
+
confirmationMethod: config.confirmationMethod ?? "event", // Default: "event"
|
49
|
+
allowArgumentModification: config.allowArgumentModification ?? true, // Default: true
|
50
|
+
autoApproveOnTimeout: config.autoApproveOnTimeout ?? false, // Default: false (safe)
|
51
|
+
auditLogging: config.auditLogging ?? false, // Default: false
|
52
|
+
customRules: config.customRules ?? [], // Default: empty array
|
53
|
+
};
|
54
|
+
if (!configWithDefaults.enabled) {
|
55
|
+
return configWithDefaults; // If disabled, don't validate other fields
|
56
|
+
}
|
57
|
+
if (!Array.isArray(configWithDefaults.dangerousActions)) {
|
58
|
+
throw new HITLConfigurationError("dangerousActions must be an array of strings");
|
59
|
+
}
|
60
|
+
if (typeof configWithDefaults.timeout !== "number" ||
|
61
|
+
configWithDefaults.timeout <= 0) {
|
62
|
+
throw new HITLConfigurationError("timeout must be a positive number (milliseconds)");
|
63
|
+
}
|
64
|
+
if (configWithDefaults.confirmationMethod !== "event") {
|
65
|
+
throw new HITLConfigurationError("confirmationMethod must be 'event' (only supported method)");
|
66
|
+
}
|
67
|
+
if (typeof configWithDefaults.allowArgumentModification !== "boolean") {
|
68
|
+
throw new HITLConfigurationError("allowArgumentModification must be a boolean");
|
69
|
+
}
|
70
|
+
return configWithDefaults;
|
71
|
+
}
|
72
|
+
/**
|
73
|
+
* Check if a tool requires confirmation based on configuration
|
74
|
+
*/
|
75
|
+
requiresConfirmation(toolName, args) {
|
76
|
+
if (!this.config.enabled) {
|
77
|
+
return false;
|
78
|
+
}
|
79
|
+
// Check dangerous actions keywords
|
80
|
+
const lowerToolName = toolName.toLowerCase();
|
81
|
+
for (const action of this.config.dangerousActions) {
|
82
|
+
if (lowerToolName.includes(action.toLowerCase())) {
|
83
|
+
return true;
|
84
|
+
}
|
85
|
+
}
|
86
|
+
// Check custom rules
|
87
|
+
if (this.config.customRules) {
|
88
|
+
for (const rule of this.config.customRules) {
|
89
|
+
if (rule.requiresConfirmation) {
|
90
|
+
try {
|
91
|
+
if (rule.condition(toolName, args)) {
|
92
|
+
return true;
|
93
|
+
}
|
94
|
+
}
|
95
|
+
catch (error) {
|
96
|
+
// Log rule evaluation error but don't fail
|
97
|
+
this.logAuditEvent("rule-evaluation-error", {
|
98
|
+
ruleName: rule.name,
|
99
|
+
toolName,
|
100
|
+
error: error instanceof Error ? error.message : String(error),
|
101
|
+
});
|
102
|
+
}
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|
106
|
+
return false;
|
107
|
+
}
|
108
|
+
/**
|
109
|
+
* Request confirmation for a tool execution
|
110
|
+
*/
|
111
|
+
async requestConfirmation(toolName, arguments_, context) {
|
112
|
+
const confirmationId = this.generateConfirmationId();
|
113
|
+
const startTime = Date.now();
|
114
|
+
// Update statistics
|
115
|
+
this.statistics.totalRequests++;
|
116
|
+
this.statistics.pendingRequests++;
|
117
|
+
return new Promise((resolve, reject) => {
|
118
|
+
// Set up timeout
|
119
|
+
const timeoutHandle = setTimeout(() => {
|
120
|
+
this.handleTimeout(confirmationId);
|
121
|
+
}, this.config.timeout);
|
122
|
+
// Store pending confirmation
|
123
|
+
const request = {
|
124
|
+
confirmationId,
|
125
|
+
toolName,
|
126
|
+
arguments: arguments_,
|
127
|
+
timestamp: startTime,
|
128
|
+
timeoutHandle,
|
129
|
+
resolve,
|
130
|
+
reject,
|
131
|
+
};
|
132
|
+
this.pendingConfirmations.set(confirmationId, request);
|
133
|
+
// Create confirmation request event
|
134
|
+
const requestEvent = {
|
135
|
+
type: "hitl:confirmation-request",
|
136
|
+
payload: {
|
137
|
+
confirmationId,
|
138
|
+
toolName,
|
139
|
+
serverId: context?.serverId,
|
140
|
+
actionType: this.generateActionDescription(toolName, arguments_),
|
141
|
+
arguments: arguments_,
|
142
|
+
metadata: {
|
143
|
+
timestamp: new Date(startTime).toISOString(),
|
144
|
+
sessionId: context?.sessionId,
|
145
|
+
userId: context?.userId,
|
146
|
+
dangerousKeywords: this.getTriggeredKeywords(toolName, arguments_),
|
147
|
+
},
|
148
|
+
timeoutMs: this.config.timeout,
|
149
|
+
allowModification: this.config.allowArgumentModification,
|
150
|
+
},
|
151
|
+
};
|
152
|
+
// Emit confirmation request event
|
153
|
+
this.emit("hitl:confirmation-request", requestEvent);
|
154
|
+
// Log audit trail if enabled
|
155
|
+
if (this.config.auditLogging) {
|
156
|
+
this.logAuditEvent("confirmation-requested", {
|
157
|
+
confirmationId,
|
158
|
+
toolName,
|
159
|
+
userId: context?.userId,
|
160
|
+
sessionId: context?.sessionId,
|
161
|
+
timestamp: startTime,
|
162
|
+
arguments: arguments_,
|
163
|
+
});
|
164
|
+
}
|
165
|
+
});
|
166
|
+
}
|
167
|
+
/**
|
168
|
+
* Process user response to confirmation request
|
169
|
+
*/
|
170
|
+
processUserResponse(confirmationId, response) {
|
171
|
+
const request = this.pendingConfirmations.get(confirmationId);
|
172
|
+
if (!request) {
|
173
|
+
logger.warn(`No pending confirmation found for ID: ${confirmationId}`);
|
174
|
+
return;
|
175
|
+
}
|
176
|
+
// Clear timeout
|
177
|
+
clearTimeout(request.timeoutHandle);
|
178
|
+
// Remove from pending
|
179
|
+
this.pendingConfirmations.delete(confirmationId);
|
180
|
+
this.statistics.pendingRequests--;
|
181
|
+
// Calculate response time
|
182
|
+
const responseTime = response.responseTime || Date.now() - request.timestamp;
|
183
|
+
// Update statistics
|
184
|
+
if (response.approved) {
|
185
|
+
this.statistics.approvedRequests++;
|
186
|
+
}
|
187
|
+
else {
|
188
|
+
this.statistics.rejectedRequests++;
|
189
|
+
}
|
190
|
+
// Update average response time
|
191
|
+
const totalResponses = this.statistics.approvedRequests + this.statistics.rejectedRequests;
|
192
|
+
this.statistics.averageResponseTime =
|
193
|
+
(this.statistics.averageResponseTime * (totalResponses - 1) +
|
194
|
+
responseTime) /
|
195
|
+
totalResponses;
|
196
|
+
// Create result
|
197
|
+
const result = {
|
198
|
+
approved: response.approved,
|
199
|
+
reason: response.reason,
|
200
|
+
modifiedArguments: response.modifiedArguments,
|
201
|
+
responseTime,
|
202
|
+
};
|
203
|
+
// Log audit trail if enabled
|
204
|
+
if (this.config.auditLogging) {
|
205
|
+
this.logAuditEvent(response.approved ? "confirmation-approved" : "confirmation-rejected", {
|
206
|
+
confirmationId,
|
207
|
+
toolName: request.toolName,
|
208
|
+
approved: response.approved,
|
209
|
+
reason: response.reason,
|
210
|
+
userId: response.userId,
|
211
|
+
responseTime,
|
212
|
+
arguments: request.arguments,
|
213
|
+
});
|
214
|
+
}
|
215
|
+
// Resolve the promise
|
216
|
+
request.resolve(result);
|
217
|
+
}
|
218
|
+
/**
|
219
|
+
* Handle confirmation timeout
|
220
|
+
*/
|
221
|
+
handleTimeout(confirmationId) {
|
222
|
+
const request = this.pendingConfirmations.get(confirmationId);
|
223
|
+
if (!request) {
|
224
|
+
return;
|
225
|
+
}
|
226
|
+
// Remove from pending
|
227
|
+
this.pendingConfirmations.delete(confirmationId);
|
228
|
+
this.statistics.pendingRequests--;
|
229
|
+
this.statistics.timedOutRequests++;
|
230
|
+
// Calculate response time (timeout duration)
|
231
|
+
const responseTime = Date.now() - request.timestamp;
|
232
|
+
// Check if auto-approve on timeout is enabled
|
233
|
+
const shouldAutoApprove = this.config.autoApproveOnTimeout === true;
|
234
|
+
// Log audit trail if enabled
|
235
|
+
if (this.config.auditLogging) {
|
236
|
+
this.logAuditEvent("confirmation-timeout", {
|
237
|
+
confirmationId,
|
238
|
+
toolName: request.toolName,
|
239
|
+
timeout: this.config.timeout,
|
240
|
+
arguments: request.arguments,
|
241
|
+
autoApproved: shouldAutoApprove,
|
242
|
+
});
|
243
|
+
}
|
244
|
+
// Create timeout event
|
245
|
+
const timeoutEvent = {
|
246
|
+
type: "hitl:timeout",
|
247
|
+
payload: {
|
248
|
+
confirmationId,
|
249
|
+
toolName: request.toolName,
|
250
|
+
timeout: this.config.timeout,
|
251
|
+
},
|
252
|
+
};
|
253
|
+
// Emit timeout event
|
254
|
+
this.emit("hitl:timeout", timeoutEvent);
|
255
|
+
if (shouldAutoApprove) {
|
256
|
+
// Auto-approve the request
|
257
|
+
this.statistics.approvedRequests++;
|
258
|
+
// Update average response time
|
259
|
+
const totalResponses = this.statistics.approvedRequests + this.statistics.rejectedRequests;
|
260
|
+
this.statistics.averageResponseTime =
|
261
|
+
(this.statistics.averageResponseTime * (totalResponses - 1) +
|
262
|
+
responseTime) /
|
263
|
+
totalResponses;
|
264
|
+
// Log auto-approval if enabled
|
265
|
+
if (this.config.auditLogging) {
|
266
|
+
this.logAuditEvent("confirmation-auto-approved", {
|
267
|
+
confirmationId,
|
268
|
+
toolName: request.toolName,
|
269
|
+
reason: "Auto-approved due to timeout",
|
270
|
+
responseTime,
|
271
|
+
arguments: request.arguments,
|
272
|
+
});
|
273
|
+
}
|
274
|
+
// Resolve with auto-approval
|
275
|
+
const result = {
|
276
|
+
approved: true,
|
277
|
+
reason: "Auto-approved due to timeout",
|
278
|
+
responseTime,
|
279
|
+
};
|
280
|
+
request.resolve(result);
|
281
|
+
}
|
282
|
+
else {
|
283
|
+
// Reject with timeout error (original behavior)
|
284
|
+
request.reject(new HITLTimeoutError(`Confirmation timeout for tool: ${request.toolName}`, confirmationId, this.config.timeout));
|
285
|
+
}
|
286
|
+
}
|
287
|
+
/**
|
288
|
+
* Set up event handlers for processing responses
|
289
|
+
*/
|
290
|
+
setupEventHandlers() {
|
291
|
+
this.on("hitl:confirmation-response", (event) => {
|
292
|
+
if (event.payload?.confirmationId) {
|
293
|
+
this.processUserResponse(event.payload.confirmationId, {
|
294
|
+
approved: event.payload.approved,
|
295
|
+
reason: event.payload.reason,
|
296
|
+
modifiedArguments: event.payload.modifiedArguments,
|
297
|
+
responseTime: event.payload.metadata?.responseTime,
|
298
|
+
userId: event.payload.metadata?.userId,
|
299
|
+
});
|
300
|
+
}
|
301
|
+
});
|
302
|
+
}
|
303
|
+
/**
|
304
|
+
* Generate unique confirmation ID
|
305
|
+
*/
|
306
|
+
generateConfirmationId() {
|
307
|
+
return `hitl-${Date.now()}-${randomUUID()}`;
|
308
|
+
}
|
309
|
+
/**
|
310
|
+
* Generate human-readable action description
|
311
|
+
*/
|
312
|
+
generateActionDescription(toolName, args) {
|
313
|
+
const lowerToolName = toolName.toLowerCase();
|
314
|
+
// Check for specific action types
|
315
|
+
if (lowerToolName.includes("delete")) {
|
316
|
+
return "Delete Operation";
|
317
|
+
}
|
318
|
+
if (lowerToolName.includes("remove")) {
|
319
|
+
return "Remove Operation";
|
320
|
+
}
|
321
|
+
if (lowerToolName.includes("update")) {
|
322
|
+
return "Update Operation";
|
323
|
+
}
|
324
|
+
if (lowerToolName.includes("create")) {
|
325
|
+
return "Create Operation";
|
326
|
+
}
|
327
|
+
if (lowerToolName.includes("drop")) {
|
328
|
+
return "Drop Operation";
|
329
|
+
}
|
330
|
+
if (lowerToolName.includes("truncate")) {
|
331
|
+
return "Truncate Operation";
|
332
|
+
}
|
333
|
+
if (lowerToolName.includes("restart")) {
|
334
|
+
return "Restart Operation";
|
335
|
+
}
|
336
|
+
if (lowerToolName.includes("stop")) {
|
337
|
+
return "Stop Operation";
|
338
|
+
}
|
339
|
+
if (lowerToolName.includes("kill")) {
|
340
|
+
return "Kill Operation";
|
341
|
+
}
|
342
|
+
// Check custom rules for custom messages
|
343
|
+
if (this.config.customRules) {
|
344
|
+
for (const rule of this.config.customRules) {
|
345
|
+
try {
|
346
|
+
if (rule.condition(toolName, args) && rule.customMessage) {
|
347
|
+
return rule.customMessage;
|
348
|
+
}
|
349
|
+
}
|
350
|
+
catch {
|
351
|
+
// Ignore rule evaluation errors
|
352
|
+
}
|
353
|
+
}
|
354
|
+
}
|
355
|
+
return `Execute ${toolName}`;
|
356
|
+
}
|
357
|
+
/**
|
358
|
+
* Get keywords that triggered HITL
|
359
|
+
*/
|
360
|
+
getTriggeredKeywords(toolName, args) {
|
361
|
+
const triggered = [];
|
362
|
+
const lowerToolName = toolName.toLowerCase();
|
363
|
+
// Check dangerous actions
|
364
|
+
for (const action of this.config.dangerousActions) {
|
365
|
+
if (lowerToolName.includes(action.toLowerCase())) {
|
366
|
+
triggered.push(action);
|
367
|
+
}
|
368
|
+
}
|
369
|
+
// Check custom rules
|
370
|
+
if (this.config.customRules) {
|
371
|
+
for (const rule of this.config.customRules) {
|
372
|
+
try {
|
373
|
+
if (rule.requiresConfirmation && rule.condition(toolName, args)) {
|
374
|
+
triggered.push(rule.name);
|
375
|
+
}
|
376
|
+
}
|
377
|
+
catch {
|
378
|
+
// Ignore rule evaluation errors
|
379
|
+
}
|
380
|
+
}
|
381
|
+
}
|
382
|
+
return triggered;
|
383
|
+
}
|
384
|
+
/**
|
385
|
+
* Log audit events for compliance and debugging
|
386
|
+
*/
|
387
|
+
logAuditEvent(eventType, data) {
|
388
|
+
const auditLog = {
|
389
|
+
timestamp: new Date().toISOString(),
|
390
|
+
eventType: eventType,
|
391
|
+
toolName: data.toolName,
|
392
|
+
userId: data.userId,
|
393
|
+
sessionId: data.sessionId,
|
394
|
+
arguments: data.arguments,
|
395
|
+
reason: data.reason,
|
396
|
+
responseTime: data.responseTime,
|
397
|
+
...data,
|
398
|
+
};
|
399
|
+
logger.info(`[HITL Audit] ${eventType}:`, auditLog);
|
400
|
+
// Emit audit event for external logging systems
|
401
|
+
this.emit("hitl:audit", auditLog);
|
402
|
+
}
|
403
|
+
/**
|
404
|
+
* Get current HITL usage statistics
|
405
|
+
*/
|
406
|
+
getStatistics() {
|
407
|
+
return { ...this.statistics };
|
408
|
+
}
|
409
|
+
/**
|
410
|
+
* Get current configuration
|
411
|
+
*/
|
412
|
+
getConfig() {
|
413
|
+
return { ...this.config };
|
414
|
+
}
|
415
|
+
/**
|
416
|
+
* Update configuration (for dynamic reconfiguration)
|
417
|
+
*/
|
418
|
+
updateConfig(newConfig) {
|
419
|
+
const updatedConfig = { ...this.config, ...newConfig };
|
420
|
+
this.config = this.validateConfig(updatedConfig);
|
421
|
+
if (this.config.auditLogging) {
|
422
|
+
this.logAuditEvent("configuration-updated", {
|
423
|
+
oldConfig: this.config,
|
424
|
+
newConfig: updatedConfig,
|
425
|
+
});
|
426
|
+
}
|
427
|
+
}
|
428
|
+
/**
|
429
|
+
* Clean up resources and reject pending confirmations
|
430
|
+
*/
|
431
|
+
cleanup() {
|
432
|
+
// Clear all pending confirmations
|
433
|
+
for (const [confirmationId, request] of this.pendingConfirmations) {
|
434
|
+
clearTimeout(request.timeoutHandle);
|
435
|
+
request.reject(new Error(`HITL cleanup: confirmation ${confirmationId} cancelled`));
|
436
|
+
}
|
437
|
+
this.pendingConfirmations.clear();
|
438
|
+
this.statistics.pendingRequests = 0;
|
439
|
+
if (this.config.auditLogging) {
|
440
|
+
this.logAuditEvent("manager-cleanup", {
|
441
|
+
clearedConfirmations: this.pendingConfirmations.size,
|
442
|
+
});
|
443
|
+
}
|
444
|
+
}
|
445
|
+
/**
|
446
|
+
* Check if manager is currently enabled
|
447
|
+
*/
|
448
|
+
isEnabled() {
|
449
|
+
return this.config.enabled;
|
450
|
+
}
|
451
|
+
/**
|
452
|
+
* Get count of pending confirmations
|
453
|
+
*/
|
454
|
+
getPendingCount() {
|
455
|
+
return this.pendingConfirmations.size;
|
456
|
+
}
|
457
|
+
}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
/**
|
2
|
+
* HITL (Human-in-the-Loop) Module
|
3
|
+
*
|
4
|
+
* Simple barrel export for HITL components.
|
5
|
+
*/
|
6
|
+
export { HITLManager } from "./hitlManager.js";
|
7
|
+
export type { HITLConfig, HITLRule, ConfirmationRequest, ConfirmationResult, ConfirmationRequestEvent, ConfirmationResponseEvent, ConfirmationTimeoutEvent, HITLStatistics, HITLAuditLog, } from "./types.js";
|
8
|
+
export { HITLError, HITLUserRejectedError, HITLTimeoutError, HITLConfigurationError, } from "./hitlErrors.js";
|
@@ -0,0 +1,9 @@
|
|
1
|
+
/**
|
2
|
+
* HITL (Human-in-the-Loop) Module
|
3
|
+
*
|
4
|
+
* Simple barrel export for HITL components.
|
5
|
+
*/
|
6
|
+
// Core HITL Manager
|
7
|
+
export { HITLManager } from "./hitlManager.js";
|
8
|
+
// Error Classes
|
9
|
+
export { HITLError, HITLUserRejectedError, HITLTimeoutError, HITLConfigurationError, } from "./hitlErrors.js";
|