@loxia-labs/loxia-autopilot-one 1.0.1
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/LICENSE +267 -0
- package/README.md +509 -0
- package/bin/cli.js +117 -0
- package/package.json +94 -0
- package/scripts/install-scanners.js +236 -0
- package/src/analyzers/CSSAnalyzer.js +297 -0
- package/src/analyzers/ConfigValidator.js +690 -0
- package/src/analyzers/ESLintAnalyzer.js +320 -0
- package/src/analyzers/JavaScriptAnalyzer.js +261 -0
- package/src/analyzers/PrettierFormatter.js +247 -0
- package/src/analyzers/PythonAnalyzer.js +266 -0
- package/src/analyzers/SecurityAnalyzer.js +729 -0
- package/src/analyzers/TypeScriptAnalyzer.js +247 -0
- package/src/analyzers/codeCloneDetector/analyzer.js +344 -0
- package/src/analyzers/codeCloneDetector/detector.js +203 -0
- package/src/analyzers/codeCloneDetector/index.js +160 -0
- package/src/analyzers/codeCloneDetector/parser.js +199 -0
- package/src/analyzers/codeCloneDetector/reporter.js +148 -0
- package/src/analyzers/codeCloneDetector/scanner.js +59 -0
- package/src/core/agentPool.js +1474 -0
- package/src/core/agentScheduler.js +2147 -0
- package/src/core/contextManager.js +709 -0
- package/src/core/messageProcessor.js +732 -0
- package/src/core/orchestrator.js +548 -0
- package/src/core/stateManager.js +877 -0
- package/src/index.js +631 -0
- package/src/interfaces/cli.js +549 -0
- package/src/interfaces/webServer.js +2162 -0
- package/src/modules/fileExplorer/controller.js +280 -0
- package/src/modules/fileExplorer/index.js +37 -0
- package/src/modules/fileExplorer/middleware.js +92 -0
- package/src/modules/fileExplorer/routes.js +125 -0
- package/src/modules/fileExplorer/types.js +44 -0
- package/src/services/aiService.js +1232 -0
- package/src/services/apiKeyManager.js +164 -0
- package/src/services/benchmarkService.js +366 -0
- package/src/services/budgetService.js +539 -0
- package/src/services/contextInjectionService.js +247 -0
- package/src/services/conversationCompactionService.js +637 -0
- package/src/services/errorHandler.js +810 -0
- package/src/services/fileAttachmentService.js +544 -0
- package/src/services/modelRouterService.js +366 -0
- package/src/services/modelsService.js +322 -0
- package/src/services/qualityInspector.js +796 -0
- package/src/services/tokenCountingService.js +536 -0
- package/src/tools/agentCommunicationTool.js +1344 -0
- package/src/tools/agentDelayTool.js +485 -0
- package/src/tools/asyncToolManager.js +604 -0
- package/src/tools/baseTool.js +800 -0
- package/src/tools/browserTool.js +920 -0
- package/src/tools/cloneDetectionTool.js +621 -0
- package/src/tools/dependencyResolverTool.js +1215 -0
- package/src/tools/fileContentReplaceTool.js +875 -0
- package/src/tools/fileSystemTool.js +1107 -0
- package/src/tools/fileTreeTool.js +853 -0
- package/src/tools/imageTool.js +901 -0
- package/src/tools/importAnalyzerTool.js +1060 -0
- package/src/tools/jobDoneTool.js +248 -0
- package/src/tools/seekTool.js +956 -0
- package/src/tools/staticAnalysisTool.js +1778 -0
- package/src/tools/taskManagerTool.js +2873 -0
- package/src/tools/terminalTool.js +2304 -0
- package/src/tools/webTool.js +1430 -0
- package/src/types/agent.js +519 -0
- package/src/types/contextReference.js +972 -0
- package/src/types/conversation.js +730 -0
- package/src/types/toolCommand.js +747 -0
- package/src/utilities/attachmentValidator.js +292 -0
- package/src/utilities/configManager.js +582 -0
- package/src/utilities/constants.js +722 -0
- package/src/utilities/directoryAccessManager.js +535 -0
- package/src/utilities/fileProcessor.js +307 -0
- package/src/utilities/logger.js +436 -0
- package/src/utilities/tagParser.js +1246 -0
- package/src/utilities/toolConstants.js +317 -0
- package/web-ui/build/index.html +15 -0
- package/web-ui/build/logo.png +0 -0
- package/web-ui/build/logo2.png +0 -0
- package/web-ui/build/static/index-CjkkcnFA.js +344 -0
- package/web-ui/build/static/index-Dy2bYbOa.css +1 -0
|
@@ -0,0 +1,747 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Command Data Model - Type definitions and validation for tool executions
|
|
3
|
+
*
|
|
4
|
+
* Purpose:
|
|
5
|
+
* - Define the structure and properties of tool commands and executions
|
|
6
|
+
* - Provide validation functions for tool command data
|
|
7
|
+
* - Handle tool execution lifecycle and state management
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { TOOL_STATUS, TOOL_NAMES, OPERATION_STATUS } from '../utilities/constants.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Tool Command data model
|
|
14
|
+
* @typedef {Object} ToolCommand
|
|
15
|
+
* @property {string} id - Unique command identifier
|
|
16
|
+
* @property {string} toolId - Tool identifier (e.g., 'terminal', 'filesys')
|
|
17
|
+
* @property {string} command - Command to execute
|
|
18
|
+
* @property {Object} parameters - Command parameters
|
|
19
|
+
* @property {string} status - Execution status (pending, executing, completed, failed)
|
|
20
|
+
* @property {string} agentId - ID of agent executing the command
|
|
21
|
+
* @property {string} conversationId - ID of parent conversation
|
|
22
|
+
* @property {string} messageId - ID of parent message
|
|
23
|
+
* @property {ToolExecution} execution - Execution details
|
|
24
|
+
* @property {ToolMetadata} metadata - Command metadata
|
|
25
|
+
* @property {string} createdAt - ISO timestamp of creation
|
|
26
|
+
* @property {string} [startedAt] - ISO timestamp when execution started
|
|
27
|
+
* @property {string} [completedAt] - ISO timestamp when execution completed
|
|
28
|
+
* @property {number} priority - Command priority (1-5)
|
|
29
|
+
* @property {number} timeout - Timeout in milliseconds
|
|
30
|
+
* @property {number} retryCount - Number of retry attempts
|
|
31
|
+
* @property {number} maxRetries - Maximum retry attempts allowed
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Tool Execution details
|
|
36
|
+
* @typedef {Object} ToolExecution
|
|
37
|
+
* @property {string} executionId - Unique execution identifier
|
|
38
|
+
* @property {Object} input - Input parameters provided to tool
|
|
39
|
+
* @property {Object} [output] - Tool execution output
|
|
40
|
+
* @property {string} [error] - Error message if execution failed
|
|
41
|
+
* @property {string} [errorCode] - Error code for programmatic handling
|
|
42
|
+
* @property {number} executionTime - Time taken for execution (ms)
|
|
43
|
+
* @property {number} memoryUsage - Memory usage during execution (bytes)
|
|
44
|
+
* @property {number} cpuUsage - CPU usage percentage
|
|
45
|
+
* @property {Object} metrics - Execution metrics and performance data
|
|
46
|
+
* @property {ExecutionLog[]} logs - Execution logs and output
|
|
47
|
+
* @property {Object} environment - Execution environment information
|
|
48
|
+
* @property {string} [workingDirectory] - Working directory for execution
|
|
49
|
+
* @property {Object} [environmentVariables] - Environment variables used
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Tool Metadata
|
|
54
|
+
* @typedef {Object} ToolMetadata
|
|
55
|
+
* @property {string} toolVersion - Version of the tool used
|
|
56
|
+
* @property {string[]} capabilities - Tool capabilities used
|
|
57
|
+
* @property {Object} configuration - Tool-specific configuration
|
|
58
|
+
* @property {boolean} requiresAuth - Whether tool requires authentication
|
|
59
|
+
* @property {string[]} dependencies - Tool dependencies
|
|
60
|
+
* @property {Object} constraints - Execution constraints
|
|
61
|
+
* @property {string[]} tags - Metadata tags
|
|
62
|
+
* @property {Object} customFields - Custom metadata fields
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Execution Log entry
|
|
67
|
+
* @typedef {Object} ExecutionLog
|
|
68
|
+
* @property {string} id - Log entry identifier
|
|
69
|
+
* @property {string} level - Log level (debug, info, warn, error)
|
|
70
|
+
* @property {string} message - Log message
|
|
71
|
+
* @property {string} timestamp - ISO timestamp
|
|
72
|
+
* @property {Object} [data] - Additional log data
|
|
73
|
+
* @property {string} [source] - Log source component
|
|
74
|
+
*/
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Tool Definition
|
|
78
|
+
* @typedef {Object} ToolDefinition
|
|
79
|
+
* @property {string} id - Tool identifier
|
|
80
|
+
* @property {string} name - Human-readable tool name
|
|
81
|
+
* @property {string} description - Tool description
|
|
82
|
+
* @property {string} version - Tool version
|
|
83
|
+
* @property {ToolCapability[]} capabilities - Tool capabilities
|
|
84
|
+
* @property {ParameterSchema} parameterSchema - Parameter validation schema
|
|
85
|
+
* @property {Object} configuration - Default configuration
|
|
86
|
+
* @property {string[]} requiredPermissions - Required permissions
|
|
87
|
+
* @property {Object} constraints - Tool constraints and limits
|
|
88
|
+
* @property {boolean} isAsync - Whether tool executes asynchronously
|
|
89
|
+
* @property {number} defaultTimeout - Default timeout in milliseconds
|
|
90
|
+
*/
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Tool Capability
|
|
94
|
+
* @typedef {Object} ToolCapability
|
|
95
|
+
* @property {string} id - Capability identifier
|
|
96
|
+
* @property {string} name - Capability name
|
|
97
|
+
* @property {string} description - Capability description
|
|
98
|
+
* @property {string[]} commands - Supported commands
|
|
99
|
+
* @property {Object} parameters - Capability-specific parameters
|
|
100
|
+
* @property {Object} constraints - Capability constraints
|
|
101
|
+
*/
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Parameter Schema
|
|
105
|
+
* @typedef {Object} ParameterSchema
|
|
106
|
+
* @property {Object} properties - Parameter definitions
|
|
107
|
+
* @property {string[]} required - Required parameter names
|
|
108
|
+
* @property {Object} additionalProperties - Additional property settings
|
|
109
|
+
* @property {Object} examples - Example parameter sets
|
|
110
|
+
*/
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Tool Command validation functions
|
|
114
|
+
*/
|
|
115
|
+
export class ToolCommandValidator {
|
|
116
|
+
/**
|
|
117
|
+
* Validate tool command data structure
|
|
118
|
+
* @param {Object} command - Tool command to validate
|
|
119
|
+
* @returns {Object} Validation result
|
|
120
|
+
*/
|
|
121
|
+
static validate(command) {
|
|
122
|
+
const errors = [];
|
|
123
|
+
const warnings = [];
|
|
124
|
+
|
|
125
|
+
// Required fields
|
|
126
|
+
if (!command.id || typeof command.id !== 'string') {
|
|
127
|
+
errors.push('Command ID is required and must be a string');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (!command.toolId || typeof command.toolId !== 'string') {
|
|
131
|
+
errors.push('Tool ID is required and must be a string');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (!command.command || typeof command.command !== 'string') {
|
|
135
|
+
errors.push('Command is required and must be a string');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (!command.agentId || typeof command.agentId !== 'string') {
|
|
139
|
+
errors.push('Agent ID is required and must be a string');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Tool ID validation
|
|
143
|
+
if (command.toolId && !Object.values(TOOL_NAMES).includes(command.toolId) && !command.toolId.startsWith('custom_')) {
|
|
144
|
+
warnings.push(`Unknown tool ID: ${command.toolId}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Status validation
|
|
148
|
+
if (command.status && !Object.values(TOOL_STATUS).includes(command.status)) {
|
|
149
|
+
errors.push(`Invalid tool status: ${command.status}`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Parameters validation
|
|
153
|
+
if (command.parameters && typeof command.parameters !== 'object') {
|
|
154
|
+
errors.push('Parameters must be an object');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Priority validation
|
|
158
|
+
if (command.priority !== undefined) {
|
|
159
|
+
if (typeof command.priority !== 'number' || command.priority < 1 || command.priority > 5) {
|
|
160
|
+
errors.push('Priority must be a number between 1 and 5');
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Timeout validation
|
|
165
|
+
if (command.timeout !== undefined) {
|
|
166
|
+
if (typeof command.timeout !== 'number' || command.timeout < 0) {
|
|
167
|
+
errors.push('Timeout must be a non-negative number');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (command.timeout > 3600000) { // 1 hour
|
|
171
|
+
warnings.push('Timeout is very long (>1 hour)');
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Retry validation
|
|
176
|
+
if (command.retryCount !== undefined && typeof command.retryCount !== 'number') {
|
|
177
|
+
errors.push('Retry count must be a number');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (command.maxRetries !== undefined && typeof command.maxRetries !== 'number') {
|
|
181
|
+
errors.push('Max retries must be a number');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (command.retryCount && command.maxRetries && command.retryCount > command.maxRetries) {
|
|
185
|
+
warnings.push('Retry count exceeds max retries');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Execution validation
|
|
189
|
+
if (command.execution) {
|
|
190
|
+
const executionValidation = this.validateExecution(command.execution);
|
|
191
|
+
errors.push(...executionValidation.errors);
|
|
192
|
+
warnings.push(...executionValidation.warnings);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Timestamp validation
|
|
196
|
+
const timestampFields = ['createdAt', 'startedAt', 'completedAt'];
|
|
197
|
+
timestampFields.forEach(field => {
|
|
198
|
+
if (command[field] && !this.isValidTimestamp(command[field])) {
|
|
199
|
+
errors.push(`Invalid timestamp for ${field}: ${command[field]}`);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
isValid: errors.length === 0,
|
|
205
|
+
errors,
|
|
206
|
+
warnings
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Validate tool execution data
|
|
212
|
+
* @param {Object} execution - Execution data to validate
|
|
213
|
+
* @returns {Object} Validation result
|
|
214
|
+
*/
|
|
215
|
+
static validateExecution(execution) {
|
|
216
|
+
const errors = [];
|
|
217
|
+
const warnings = [];
|
|
218
|
+
|
|
219
|
+
if (!execution.executionId || typeof execution.executionId !== 'string') {
|
|
220
|
+
errors.push('Execution ID is required and must be a string');
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (!execution.input || typeof execution.input !== 'object') {
|
|
224
|
+
errors.push('Execution input is required and must be an object');
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (execution.executionTime !== undefined) {
|
|
228
|
+
if (typeof execution.executionTime !== 'number' || execution.executionTime < 0) {
|
|
229
|
+
errors.push('Execution time must be a non-negative number');
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (execution.memoryUsage !== undefined) {
|
|
234
|
+
if (typeof execution.memoryUsage !== 'number' || execution.memoryUsage < 0) {
|
|
235
|
+
errors.push('Memory usage must be a non-negative number');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (execution.cpuUsage !== undefined) {
|
|
240
|
+
if (typeof execution.cpuUsage !== 'number' || execution.cpuUsage < 0 || execution.cpuUsage > 100) {
|
|
241
|
+
errors.push('CPU usage must be a number between 0 and 100');
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (execution.logs && !Array.isArray(execution.logs)) {
|
|
246
|
+
errors.push('Execution logs must be an array');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (execution.logs) {
|
|
250
|
+
execution.logs.forEach((log, index) => {
|
|
251
|
+
if (!log.level || !log.message || !log.timestamp) {
|
|
252
|
+
errors.push(`Log entry ${index} missing required fields`);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return { errors, warnings };
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Validate tool definition
|
|
262
|
+
* @param {Object} toolDef - Tool definition to validate
|
|
263
|
+
* @returns {Object} Validation result
|
|
264
|
+
*/
|
|
265
|
+
static validateToolDefinition(toolDef) {
|
|
266
|
+
const errors = [];
|
|
267
|
+
const warnings = [];
|
|
268
|
+
|
|
269
|
+
// Required fields
|
|
270
|
+
if (!toolDef.id || typeof toolDef.id !== 'string') {
|
|
271
|
+
errors.push('Tool ID is required and must be a string');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (!toolDef.name || typeof toolDef.name !== 'string') {
|
|
275
|
+
errors.push('Tool name is required and must be a string');
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (!toolDef.description || typeof toolDef.description !== 'string') {
|
|
279
|
+
errors.push('Tool description is required and must be a string');
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (!toolDef.version || typeof toolDef.version !== 'string') {
|
|
283
|
+
errors.push('Tool version is required and must be a string');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Capabilities validation
|
|
287
|
+
if (!toolDef.capabilities || !Array.isArray(toolDef.capabilities)) {
|
|
288
|
+
errors.push('Tool capabilities are required and must be an array');
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (toolDef.capabilities && toolDef.capabilities.length === 0) {
|
|
292
|
+
warnings.push('Tool has no capabilities defined');
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Parameter schema validation
|
|
296
|
+
if (toolDef.parameterSchema && typeof toolDef.parameterSchema !== 'object') {
|
|
297
|
+
errors.push('Parameter schema must be an object');
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Timeout validation
|
|
301
|
+
if (toolDef.defaultTimeout !== undefined) {
|
|
302
|
+
if (typeof toolDef.defaultTimeout !== 'number' || toolDef.defaultTimeout <= 0) {
|
|
303
|
+
errors.push('Default timeout must be a positive number');
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return { errors, warnings };
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Validate command parameters against tool definition
|
|
312
|
+
* @param {Object} parameters - Parameters to validate
|
|
313
|
+
* @param {ParameterSchema} schema - Parameter schema
|
|
314
|
+
* @returns {Object} Validation result
|
|
315
|
+
*/
|
|
316
|
+
static validateParameters(parameters, schema) {
|
|
317
|
+
const errors = [];
|
|
318
|
+
const warnings = [];
|
|
319
|
+
|
|
320
|
+
if (!schema || !schema.properties) {
|
|
321
|
+
return { errors: [], warnings: ['No parameter schema provided'] };
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Check required parameters
|
|
325
|
+
if (schema.required) {
|
|
326
|
+
schema.required.forEach(paramName => {
|
|
327
|
+
if (!(paramName in parameters)) {
|
|
328
|
+
errors.push(`Required parameter missing: ${paramName}`);
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Validate parameter types and constraints
|
|
334
|
+
Object.entries(parameters).forEach(([paramName, paramValue]) => {
|
|
335
|
+
const paramDef = schema.properties[paramName];
|
|
336
|
+
|
|
337
|
+
if (!paramDef) {
|
|
338
|
+
if (!schema.additionalProperties) {
|
|
339
|
+
warnings.push(`Unknown parameter: ${paramName}`);
|
|
340
|
+
}
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Type validation
|
|
345
|
+
if (paramDef.type) {
|
|
346
|
+
const actualType = Array.isArray(paramValue) ? 'array' : typeof paramValue;
|
|
347
|
+
if (actualType !== paramDef.type) {
|
|
348
|
+
errors.push(`Parameter ${paramName} must be of type ${paramDef.type}, got ${actualType}`);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Range validation for numbers
|
|
353
|
+
if (paramDef.type === 'number') {
|
|
354
|
+
if (paramDef.minimum !== undefined && paramValue < paramDef.minimum) {
|
|
355
|
+
errors.push(`Parameter ${paramName} must be >= ${paramDef.minimum}`);
|
|
356
|
+
}
|
|
357
|
+
if (paramDef.maximum !== undefined && paramValue > paramDef.maximum) {
|
|
358
|
+
errors.push(`Parameter ${paramName} must be <= ${paramDef.maximum}`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Length validation for strings
|
|
363
|
+
if (paramDef.type === 'string') {
|
|
364
|
+
if (paramDef.minLength !== undefined && paramValue.length < paramDef.minLength) {
|
|
365
|
+
errors.push(`Parameter ${paramName} must be at least ${paramDef.minLength} characters`);
|
|
366
|
+
}
|
|
367
|
+
if (paramDef.maxLength !== undefined && paramValue.length > paramDef.maxLength) {
|
|
368
|
+
errors.push(`Parameter ${paramName} must be at most ${paramDef.maxLength} characters`);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Enum validation
|
|
373
|
+
if (paramDef.enum && !paramDef.enum.includes(paramValue)) {
|
|
374
|
+
errors.push(`Parameter ${paramName} must be one of: ${paramDef.enum.join(', ')}`);
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
return { errors, warnings };
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Check if a timestamp is valid ISO string
|
|
383
|
+
* @param {string} timestamp - Timestamp to validate
|
|
384
|
+
* @returns {boolean} True if valid
|
|
385
|
+
*/
|
|
386
|
+
static isValidTimestamp(timestamp) {
|
|
387
|
+
if (typeof timestamp !== 'string') return false;
|
|
388
|
+
const date = new Date(timestamp);
|
|
389
|
+
return date instanceof Date && !isNaN(date.getTime());
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Tool Command factory functions
|
|
395
|
+
*/
|
|
396
|
+
export class ToolCommandFactory {
|
|
397
|
+
/**
|
|
398
|
+
* Create a new tool command
|
|
399
|
+
* @param {string} toolId - Tool identifier
|
|
400
|
+
* @param {string} command - Command to execute
|
|
401
|
+
* @param {Object} parameters - Command parameters
|
|
402
|
+
* @param {Object} options - Additional options
|
|
403
|
+
* @returns {ToolCommand} New tool command object
|
|
404
|
+
*/
|
|
405
|
+
static create(toolId, command, parameters, options = {}) {
|
|
406
|
+
const now = new Date().toISOString();
|
|
407
|
+
const commandId = this.generateCommandId();
|
|
408
|
+
const executionId = this.generateExecutionId();
|
|
409
|
+
|
|
410
|
+
return {
|
|
411
|
+
id: commandId,
|
|
412
|
+
toolId,
|
|
413
|
+
command,
|
|
414
|
+
parameters: parameters || {},
|
|
415
|
+
status: TOOL_STATUS.PENDING,
|
|
416
|
+
agentId: options.agentId || '',
|
|
417
|
+
conversationId: options.conversationId || '',
|
|
418
|
+
messageId: options.messageId || '',
|
|
419
|
+
execution: {
|
|
420
|
+
executionId,
|
|
421
|
+
input: { command, parameters },
|
|
422
|
+
output: null,
|
|
423
|
+
error: null,
|
|
424
|
+
errorCode: null,
|
|
425
|
+
executionTime: 0,
|
|
426
|
+
memoryUsage: 0,
|
|
427
|
+
cpuUsage: 0,
|
|
428
|
+
metrics: {},
|
|
429
|
+
logs: [],
|
|
430
|
+
environment: options.environment || {},
|
|
431
|
+
workingDirectory: options.workingDirectory || null,
|
|
432
|
+
environmentVariables: options.environmentVariables || {}
|
|
433
|
+
},
|
|
434
|
+
metadata: this.createDefaultMetadata(options.metadata),
|
|
435
|
+
createdAt: now,
|
|
436
|
+
startedAt: null,
|
|
437
|
+
completedAt: null,
|
|
438
|
+
priority: options.priority || 3,
|
|
439
|
+
timeout: options.timeout || 30000,
|
|
440
|
+
retryCount: 0,
|
|
441
|
+
maxRetries: options.maxRetries || 3
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Create execution log entry
|
|
447
|
+
* @param {string} level - Log level
|
|
448
|
+
* @param {string} message - Log message
|
|
449
|
+
* @param {Object} data - Additional log data
|
|
450
|
+
* @returns {ExecutionLog} Log entry
|
|
451
|
+
*/
|
|
452
|
+
static createLogEntry(level, message, data = null) {
|
|
453
|
+
return {
|
|
454
|
+
id: this.generateLogId(),
|
|
455
|
+
level,
|
|
456
|
+
message,
|
|
457
|
+
timestamp: new Date().toISOString(),
|
|
458
|
+
data,
|
|
459
|
+
source: 'tool-execution'
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Create default tool metadata
|
|
465
|
+
* @param {Object} overrides - Metadata overrides
|
|
466
|
+
* @returns {ToolMetadata} Default metadata
|
|
467
|
+
*/
|
|
468
|
+
static createDefaultMetadata(overrides = {}) {
|
|
469
|
+
return {
|
|
470
|
+
toolVersion: '1.0.0',
|
|
471
|
+
capabilities: [],
|
|
472
|
+
configuration: {},
|
|
473
|
+
requiresAuth: false,
|
|
474
|
+
dependencies: [],
|
|
475
|
+
constraints: {},
|
|
476
|
+
tags: [],
|
|
477
|
+
customFields: {},
|
|
478
|
+
...overrides
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Generate unique command ID
|
|
484
|
+
* @returns {string} Unique command ID
|
|
485
|
+
*/
|
|
486
|
+
static generateCommandId() {
|
|
487
|
+
const timestamp = Date.now().toString(36);
|
|
488
|
+
const random = Math.random().toString(36).substr(2, 9);
|
|
489
|
+
return `cmd_${timestamp}_${random}`;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Generate unique execution ID
|
|
494
|
+
* @returns {string} Unique execution ID
|
|
495
|
+
*/
|
|
496
|
+
static generateExecutionId() {
|
|
497
|
+
const timestamp = Date.now().toString(36);
|
|
498
|
+
const random = Math.random().toString(36).substr(2, 9);
|
|
499
|
+
return `exec_${timestamp}_${random}`;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Generate unique log ID
|
|
504
|
+
* @returns {string} Unique log ID
|
|
505
|
+
*/
|
|
506
|
+
static generateLogId() {
|
|
507
|
+
const timestamp = Date.now().toString(36);
|
|
508
|
+
const random = Math.random().toString(36).substr(2, 6);
|
|
509
|
+
return `log_${timestamp}_${random}`;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Tool Command utility functions
|
|
515
|
+
*/
|
|
516
|
+
export class ToolCommandUtils {
|
|
517
|
+
/**
|
|
518
|
+
* Check if command is still pending
|
|
519
|
+
* @param {ToolCommand} command - Command to check
|
|
520
|
+
* @returns {boolean} True if pending
|
|
521
|
+
*/
|
|
522
|
+
static isPending(command) {
|
|
523
|
+
return command.status === TOOL_STATUS.PENDING;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Check if command is currently executing
|
|
528
|
+
* @param {ToolCommand} command - Command to check
|
|
529
|
+
* @returns {boolean} True if executing
|
|
530
|
+
*/
|
|
531
|
+
static isExecuting(command) {
|
|
532
|
+
return command.status === TOOL_STATUS.EXECUTING;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Check if command has completed successfully
|
|
537
|
+
* @param {ToolCommand} command - Command to check
|
|
538
|
+
* @returns {boolean} True if completed
|
|
539
|
+
*/
|
|
540
|
+
static isCompleted(command) {
|
|
541
|
+
return command.status === TOOL_STATUS.COMPLETED;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Check if command has failed
|
|
546
|
+
* @param {ToolCommand} command - Command to check
|
|
547
|
+
* @returns {boolean} True if failed
|
|
548
|
+
*/
|
|
549
|
+
static isFailed(command) {
|
|
550
|
+
return command.status === TOOL_STATUS.FAILED;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Check if command has timed out
|
|
555
|
+
* @param {ToolCommand} command - Command to check
|
|
556
|
+
* @returns {boolean} True if timed out
|
|
557
|
+
*/
|
|
558
|
+
static isTimedOut(command) {
|
|
559
|
+
if (!command.startedAt || command.status !== TOOL_STATUS.EXECUTING) {
|
|
560
|
+
return false;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
const startTime = new Date(command.startedAt);
|
|
564
|
+
const now = new Date();
|
|
565
|
+
const elapsed = now.getTime() - startTime.getTime();
|
|
566
|
+
|
|
567
|
+
return elapsed > command.timeout;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Calculate command execution time
|
|
572
|
+
* @param {ToolCommand} command - Command to analyze
|
|
573
|
+
* @returns {number|null} Execution time in milliseconds, null if not applicable
|
|
574
|
+
*/
|
|
575
|
+
static getExecutionTime(command) {
|
|
576
|
+
if (!command.startedAt) return null;
|
|
577
|
+
|
|
578
|
+
const endTime = command.completedAt ? new Date(command.completedAt) : new Date();
|
|
579
|
+
const startTime = new Date(command.startedAt);
|
|
580
|
+
|
|
581
|
+
return endTime.getTime() - startTime.getTime();
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Get command progress information
|
|
586
|
+
* @param {ToolCommand} command - Command to analyze
|
|
587
|
+
* @returns {Object} Progress information
|
|
588
|
+
*/
|
|
589
|
+
static getProgress(command) {
|
|
590
|
+
const executionTime = this.getExecutionTime(command);
|
|
591
|
+
const isTimedOut = this.isTimedOut(command);
|
|
592
|
+
|
|
593
|
+
let progressPercentage = 0;
|
|
594
|
+
if (command.status === TOOL_STATUS.COMPLETED) {
|
|
595
|
+
progressPercentage = 100;
|
|
596
|
+
} else if (command.status === TOOL_STATUS.EXECUTING && executionTime) {
|
|
597
|
+
// Estimate progress based on execution time vs timeout
|
|
598
|
+
progressPercentage = Math.min(95, (executionTime / command.timeout) * 100);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
return {
|
|
602
|
+
status: command.status,
|
|
603
|
+
percentage: Math.round(progressPercentage),
|
|
604
|
+
executionTime,
|
|
605
|
+
isTimedOut,
|
|
606
|
+
remainingTime: command.status === TOOL_STATUS.EXECUTING && executionTime
|
|
607
|
+
? Math.max(0, command.timeout - executionTime)
|
|
608
|
+
: null
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Extract key metrics from command execution
|
|
614
|
+
* @param {ToolCommand} command - Command to analyze
|
|
615
|
+
* @returns {Object} Execution metrics
|
|
616
|
+
*/
|
|
617
|
+
static getMetrics(command) {
|
|
618
|
+
const execution = command.execution || {};
|
|
619
|
+
const progress = this.getProgress(command);
|
|
620
|
+
|
|
621
|
+
return {
|
|
622
|
+
executionTime: execution.executionTime || progress.executionTime || 0,
|
|
623
|
+
memoryUsage: execution.memoryUsage || 0,
|
|
624
|
+
cpuUsage: execution.cpuUsage || 0,
|
|
625
|
+
status: command.status,
|
|
626
|
+
retryCount: command.retryCount,
|
|
627
|
+
priority: command.priority,
|
|
628
|
+
logEntries: execution.logs ? execution.logs.length : 0,
|
|
629
|
+
hasError: !!execution.error,
|
|
630
|
+
errorCode: execution.errorCode || null
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Format command for display
|
|
636
|
+
* @param {ToolCommand} command - Command to format
|
|
637
|
+
* @returns {Object} Formatted command data
|
|
638
|
+
*/
|
|
639
|
+
static formatForDisplay(command) {
|
|
640
|
+
const progress = this.getProgress(command);
|
|
641
|
+
const metrics = this.getMetrics(command);
|
|
642
|
+
|
|
643
|
+
return {
|
|
644
|
+
id: command.id,
|
|
645
|
+
toolId: command.toolId,
|
|
646
|
+
command: command.command,
|
|
647
|
+
status: command.status,
|
|
648
|
+
progress: progress.percentage,
|
|
649
|
+
executionTime: metrics.executionTime,
|
|
650
|
+
createdAt: command.createdAt,
|
|
651
|
+
startedAt: command.startedAt,
|
|
652
|
+
completedAt: command.completedAt,
|
|
653
|
+
hasError: metrics.hasError,
|
|
654
|
+
retryCount: command.retryCount
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Sanitize command for API responses
|
|
660
|
+
* @param {ToolCommand} command - Command to sanitize
|
|
661
|
+
* @returns {Object} Sanitized command data
|
|
662
|
+
*/
|
|
663
|
+
static sanitize(command) {
|
|
664
|
+
const sanitized = { ...command };
|
|
665
|
+
|
|
666
|
+
// Remove sensitive execution data
|
|
667
|
+
if (sanitized.execution) {
|
|
668
|
+
delete sanitized.execution.environmentVariables;
|
|
669
|
+
delete sanitized.execution.environment;
|
|
670
|
+
|
|
671
|
+
// Truncate long logs
|
|
672
|
+
if (sanitized.execution.logs && sanitized.execution.logs.length > 10) {
|
|
673
|
+
sanitized.execution.logs = sanitized.execution.logs.slice(-10);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
// Remove sensitive parameters
|
|
678
|
+
if (sanitized.parameters) {
|
|
679
|
+
const sensitiveKeys = ['password', 'token', 'secret', 'key', 'auth'];
|
|
680
|
+
Object.keys(sanitized.parameters).forEach(key => {
|
|
681
|
+
if (sensitiveKeys.some(sensitive => key.toLowerCase().includes(sensitive))) {
|
|
682
|
+
sanitized.parameters[key] = '[REDACTED]';
|
|
683
|
+
}
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
return sanitized;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Create command summary for reporting
|
|
692
|
+
* @param {ToolCommand[]} commands - Commands to summarize
|
|
693
|
+
* @returns {Object} Command summary
|
|
694
|
+
*/
|
|
695
|
+
static summarizeCommands(commands) {
|
|
696
|
+
const summary = {
|
|
697
|
+
total: commands.length,
|
|
698
|
+
byStatus: {},
|
|
699
|
+
byTool: {},
|
|
700
|
+
totalExecutionTime: 0,
|
|
701
|
+
averageExecutionTime: 0,
|
|
702
|
+
successRate: 0,
|
|
703
|
+
mostUsedTools: [],
|
|
704
|
+
recentCommands: []
|
|
705
|
+
};
|
|
706
|
+
|
|
707
|
+
// Count by status
|
|
708
|
+
Object.values(TOOL_STATUS).forEach(status => {
|
|
709
|
+
summary.byStatus[status] = commands.filter(cmd => cmd.status === status).length;
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
// Count by tool
|
|
713
|
+
commands.forEach(command => {
|
|
714
|
+
summary.byTool[command.toolId] = (summary.byTool[command.toolId] || 0) + 1;
|
|
715
|
+
|
|
716
|
+
const executionTime = this.getExecutionTime(command) || 0;
|
|
717
|
+
summary.totalExecutionTime += executionTime;
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
// Calculate averages and rates
|
|
721
|
+
if (commands.length > 0) {
|
|
722
|
+
summary.averageExecutionTime = summary.totalExecutionTime / commands.length;
|
|
723
|
+
const successfulCommands = summary.byStatus[TOOL_STATUS.COMPLETED] || 0;
|
|
724
|
+
summary.successRate = (successfulCommands / commands.length) * 100;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// Most used tools
|
|
728
|
+
summary.mostUsedTools = Object.entries(summary.byTool)
|
|
729
|
+
.sort((a, b) => b[1] - a[1])
|
|
730
|
+
.slice(0, 5)
|
|
731
|
+
.map(([toolId, count]) => ({ toolId, count }));
|
|
732
|
+
|
|
733
|
+
// Recent commands
|
|
734
|
+
summary.recentCommands = commands
|
|
735
|
+
.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
|
|
736
|
+
.slice(0, 10)
|
|
737
|
+
.map(cmd => this.formatForDisplay(cmd));
|
|
738
|
+
|
|
739
|
+
return summary;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
export default {
|
|
744
|
+
ToolCommandValidator,
|
|
745
|
+
ToolCommandFactory,
|
|
746
|
+
ToolCommandUtils
|
|
747
|
+
};
|