@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.
Files changed (80) hide show
  1. package/LICENSE +267 -0
  2. package/README.md +509 -0
  3. package/bin/cli.js +117 -0
  4. package/package.json +94 -0
  5. package/scripts/install-scanners.js +236 -0
  6. package/src/analyzers/CSSAnalyzer.js +297 -0
  7. package/src/analyzers/ConfigValidator.js +690 -0
  8. package/src/analyzers/ESLintAnalyzer.js +320 -0
  9. package/src/analyzers/JavaScriptAnalyzer.js +261 -0
  10. package/src/analyzers/PrettierFormatter.js +247 -0
  11. package/src/analyzers/PythonAnalyzer.js +266 -0
  12. package/src/analyzers/SecurityAnalyzer.js +729 -0
  13. package/src/analyzers/TypeScriptAnalyzer.js +247 -0
  14. package/src/analyzers/codeCloneDetector/analyzer.js +344 -0
  15. package/src/analyzers/codeCloneDetector/detector.js +203 -0
  16. package/src/analyzers/codeCloneDetector/index.js +160 -0
  17. package/src/analyzers/codeCloneDetector/parser.js +199 -0
  18. package/src/analyzers/codeCloneDetector/reporter.js +148 -0
  19. package/src/analyzers/codeCloneDetector/scanner.js +59 -0
  20. package/src/core/agentPool.js +1474 -0
  21. package/src/core/agentScheduler.js +2147 -0
  22. package/src/core/contextManager.js +709 -0
  23. package/src/core/messageProcessor.js +732 -0
  24. package/src/core/orchestrator.js +548 -0
  25. package/src/core/stateManager.js +877 -0
  26. package/src/index.js +631 -0
  27. package/src/interfaces/cli.js +549 -0
  28. package/src/interfaces/webServer.js +2162 -0
  29. package/src/modules/fileExplorer/controller.js +280 -0
  30. package/src/modules/fileExplorer/index.js +37 -0
  31. package/src/modules/fileExplorer/middleware.js +92 -0
  32. package/src/modules/fileExplorer/routes.js +125 -0
  33. package/src/modules/fileExplorer/types.js +44 -0
  34. package/src/services/aiService.js +1232 -0
  35. package/src/services/apiKeyManager.js +164 -0
  36. package/src/services/benchmarkService.js +366 -0
  37. package/src/services/budgetService.js +539 -0
  38. package/src/services/contextInjectionService.js +247 -0
  39. package/src/services/conversationCompactionService.js +637 -0
  40. package/src/services/errorHandler.js +810 -0
  41. package/src/services/fileAttachmentService.js +544 -0
  42. package/src/services/modelRouterService.js +366 -0
  43. package/src/services/modelsService.js +322 -0
  44. package/src/services/qualityInspector.js +796 -0
  45. package/src/services/tokenCountingService.js +536 -0
  46. package/src/tools/agentCommunicationTool.js +1344 -0
  47. package/src/tools/agentDelayTool.js +485 -0
  48. package/src/tools/asyncToolManager.js +604 -0
  49. package/src/tools/baseTool.js +800 -0
  50. package/src/tools/browserTool.js +920 -0
  51. package/src/tools/cloneDetectionTool.js +621 -0
  52. package/src/tools/dependencyResolverTool.js +1215 -0
  53. package/src/tools/fileContentReplaceTool.js +875 -0
  54. package/src/tools/fileSystemTool.js +1107 -0
  55. package/src/tools/fileTreeTool.js +853 -0
  56. package/src/tools/imageTool.js +901 -0
  57. package/src/tools/importAnalyzerTool.js +1060 -0
  58. package/src/tools/jobDoneTool.js +248 -0
  59. package/src/tools/seekTool.js +956 -0
  60. package/src/tools/staticAnalysisTool.js +1778 -0
  61. package/src/tools/taskManagerTool.js +2873 -0
  62. package/src/tools/terminalTool.js +2304 -0
  63. package/src/tools/webTool.js +1430 -0
  64. package/src/types/agent.js +519 -0
  65. package/src/types/contextReference.js +972 -0
  66. package/src/types/conversation.js +730 -0
  67. package/src/types/toolCommand.js +747 -0
  68. package/src/utilities/attachmentValidator.js +292 -0
  69. package/src/utilities/configManager.js +582 -0
  70. package/src/utilities/constants.js +722 -0
  71. package/src/utilities/directoryAccessManager.js +535 -0
  72. package/src/utilities/fileProcessor.js +307 -0
  73. package/src/utilities/logger.js +436 -0
  74. package/src/utilities/tagParser.js +1246 -0
  75. package/src/utilities/toolConstants.js +317 -0
  76. package/web-ui/build/index.html +15 -0
  77. package/web-ui/build/logo.png +0 -0
  78. package/web-ui/build/logo2.png +0 -0
  79. package/web-ui/build/static/index-CjkkcnFA.js +344 -0
  80. package/web-ui/build/static/index-Dy2bYbOa.css +1 -0
@@ -0,0 +1,485 @@
1
+ /**
2
+ * AgentDelayTool - Allows agents to pause their activity for specified duration
3
+ *
4
+ * Purpose:
5
+ * - Pause agent activity during waiting periods
6
+ * - Prevent unnecessary message exchanges
7
+ * - Handle installation and startup delays
8
+ * - Manage agent status during long operations
9
+ */
10
+
11
+ import { BaseTool } from './baseTool.js';
12
+ import TagParser from '../utilities/tagParser.js';
13
+
14
+ import {
15
+ TOOL_STATUS,
16
+ SYSTEM_DEFAULTS,
17
+ AGENT_STATUS
18
+ } from '../utilities/constants.js';
19
+
20
+ class AgentDelayTool extends BaseTool {
21
+ constructor(config = {}, logger = null, agentPool = null) {
22
+ super(config, logger);
23
+
24
+ this.agentPool = agentPool;
25
+ this.maxPauseDuration = config.maxDuration || SYSTEM_DEFAULTS.MAX_PAUSE_DURATION;
26
+ this.minPauseDuration = config.minDuration || 1;
27
+
28
+ // Tool metadata
29
+ this.requiresProject = false;
30
+ this.isAsync = false; // Synchronous - immediately updates agent status
31
+ }
32
+
33
+ /**
34
+ * Get tool description for LLM consumption
35
+ * @returns {string} Tool description
36
+ */
37
+ getDescription() {
38
+ return `
39
+ Agent Delay Tool: Pause agent activity for a specified duration to prevent unnecessary message exchanges during waiting periods.
40
+
41
+ USAGE:
42
+ [tool id="agentdelay"]
43
+ <pause-duration>30</pause-duration>
44
+ <reason>Waiting for npm install to complete</reason>
45
+ [/tool]
46
+
47
+ PARAMETERS:
48
+ - pause-duration: Number of seconds to pause (${this.minPauseDuration}-${this.maxPauseDuration})
49
+ - reason: Optional explanation for the pause
50
+
51
+ USE CASES:
52
+ - After running 'npm install' or similar long-running commands
53
+ - Waiting for services to start up
54
+ - Allowing time for file system operations to complete
55
+ - Preventing rapid status checking loops
56
+ - During build processes or compilation
57
+
58
+ BEHAVIOR:
59
+ The agent will be marked as '${AGENT_STATUS.PAUSED}' and will not process new messages until the duration expires.
60
+ Other agents can still send messages, but they will be queued until the agent resumes.
61
+
62
+ EXAMPLES:
63
+ Basic pause for 1 minute:
64
+ [tool id="agentdelay"]
65
+ <pause-duration>60</pause-duration>
66
+ [/tool]
67
+
68
+ Pause with reason:
69
+ [tool id="agentdelay"]
70
+ <pause-duration>120</pause-duration>
71
+ <reason>Installing dependencies</reason>
72
+ [/tool]
73
+
74
+ Brief pause for service startup:
75
+ [tool id="agentdelay"]
76
+ <pause-duration>30</pause-duration>
77
+ <reason>Waiting for server startup</reason>
78
+ [/tool]
79
+
80
+ IMPORTANT: Use this tool judiciously. Only pause when genuinely waiting for external processes.
81
+ The maximum pause duration is ${this.maxPauseDuration} seconds (${Math.floor(this.maxPauseDuration / 60)} minutes).
82
+ `;
83
+ }
84
+
85
+ /**
86
+ * Parse parameters from tool command content
87
+ * @param {string} content - Raw tool command content
88
+ * @returns {Object} Parsed parameters
89
+ */
90
+ parseParameters(content) {
91
+ try {
92
+ // Extract pause-duration and reason using TagParser
93
+ const durationMatches = TagParser.extractContent(content, 'pause-duration');
94
+ const reasonMatches = TagParser.extractContent(content, 'reason');
95
+
96
+ const duration = durationMatches.length > 0 ? parseInt(durationMatches[0], 10) : null;
97
+ const reason = reasonMatches.length > 0 ? reasonMatches[0].trim() : 'Agent pause requested';
98
+
99
+ return {
100
+ duration,
101
+ reason,
102
+ rawContent: content.trim()
103
+ };
104
+
105
+ } catch (error) {
106
+ throw new Error(`Failed to parse agent delay parameters: ${error.message}`);
107
+ }
108
+ }
109
+
110
+ /**
111
+ * Get required parameters
112
+ * @returns {Array<string>} Array of required parameter names
113
+ */
114
+ getRequiredParameters() {
115
+ return ['duration'];
116
+ }
117
+
118
+ /**
119
+ * Validate parameter types
120
+ * @param {Object} params - Parameters to validate
121
+ * @returns {Object} Validation result
122
+ */
123
+ validateParameterTypes(params) {
124
+ const errors = [];
125
+
126
+ if (params.duration !== null && params.duration !== undefined) {
127
+ if (typeof params.duration !== 'number' || isNaN(params.duration)) {
128
+ errors.push('pause-duration must be a valid number');
129
+ }
130
+ }
131
+
132
+ if (params.reason && typeof params.reason !== 'string') {
133
+ errors.push('reason must be a string');
134
+ }
135
+
136
+ return {
137
+ valid: errors.length === 0,
138
+ errors
139
+ };
140
+ }
141
+
142
+ /**
143
+ * Custom parameter validation
144
+ * @param {Object} params - Parameters to validate
145
+ * @returns {Object} Validation result
146
+ */
147
+ customValidateParameters(params) {
148
+ const errors = [];
149
+
150
+ if (params.duration === null || params.duration === undefined) {
151
+ errors.push('pause-duration is required');
152
+ } else {
153
+ if (params.duration < this.minPauseDuration) {
154
+ errors.push(`pause-duration must be at least ${this.minPauseDuration} second(s)`);
155
+ }
156
+
157
+ if (params.duration > this.maxPauseDuration) {
158
+ errors.push(`pause-duration cannot exceed ${this.maxPauseDuration} seconds (${Math.floor(this.maxPauseDuration / 60)} minutes)`);
159
+ }
160
+
161
+ if (!Number.isInteger(params.duration)) {
162
+ errors.push('pause-duration must be a whole number of seconds');
163
+ }
164
+ }
165
+
166
+ if (params.reason && params.reason.length > 200) {
167
+ errors.push('reason cannot exceed 200 characters');
168
+ }
169
+
170
+ return {
171
+ valid: errors.length === 0,
172
+ errors
173
+ };
174
+ }
175
+
176
+ /**
177
+ * Execute tool with parsed parameters
178
+ * @param {Object} params - Parsed parameters
179
+ * @param {Object} context - Execution context
180
+ * @returns {Promise<Object>} Execution result
181
+ */
182
+ async execute(params, context) {
183
+ const { duration, reason } = params;
184
+ const { agentId } = context;
185
+
186
+ if (!agentId) {
187
+ throw new Error('Agent ID is required for agent delay tool');
188
+ }
189
+
190
+ if (!this.agentPool) {
191
+ throw new Error('Agent pool not available - cannot pause agent');
192
+ }
193
+
194
+ try {
195
+ // Calculate pause end time
196
+ const pausedUntil = new Date(Date.now() + duration * 1000);
197
+
198
+ // Pause the agent via agent pool
199
+ const pauseResult = await this.agentPool.pauseAgent(agentId, pausedUntil, reason);
200
+
201
+ // Also set delayEndTime for the new scheduler architecture
202
+ const agent = await this.agentPool.getAgent(agentId);
203
+ if (agent) {
204
+ agent.delayEndTime = pausedUntil.toISOString();
205
+ await this.agentPool.persistAgentState(agentId);
206
+ }
207
+
208
+ if (!pauseResult.success) {
209
+ throw new Error(`Failed to pause agent: ${pauseResult.message || 'Unknown error'}`);
210
+ }
211
+
212
+ const result = {
213
+ success: true,
214
+ action: 'agent-pause',
215
+ agentId,
216
+ pauseDuration: duration,
217
+ pausedUntil: pausedUntil.toISOString(),
218
+ reason,
219
+ message: `Agent will resume activity in ${duration} second${duration !== 1 ? 's' : ''}`,
220
+ resumeTime: this.formatResumeTime(pausedUntil),
221
+ toolUsed: 'agent-delay'
222
+ };
223
+
224
+ this.logger?.info(`Agent paused via agent-delay tool: ${agentId}`, {
225
+ duration,
226
+ reason,
227
+ pausedUntil: pausedUntil.toISOString(),
228
+ toolUsage: true
229
+ });
230
+
231
+ return result;
232
+
233
+ } catch (error) {
234
+ this.logger?.error(`Agent delay tool execution failed: ${error.message}`, {
235
+ agentId,
236
+ duration,
237
+ reason,
238
+ error: error.stack
239
+ });
240
+
241
+ throw error;
242
+ }
243
+ }
244
+
245
+ /**
246
+ * Get supported actions for this tool
247
+ * @returns {Array<string>} Array of supported action names
248
+ */
249
+ getSupportedActions() {
250
+ return ['pause', 'delay'];
251
+ }
252
+
253
+ /**
254
+ * Get parameter schema for validation
255
+ * @returns {Object} Parameter schema
256
+ */
257
+ getParameterSchema() {
258
+ return {
259
+ type: 'object',
260
+ properties: {
261
+ duration: {
262
+ type: 'integer',
263
+ minimum: this.minPauseDuration,
264
+ maximum: this.maxPauseDuration,
265
+ description: 'Number of seconds to pause agent activity'
266
+ },
267
+ reason: {
268
+ type: 'string',
269
+ maxLength: 200,
270
+ description: 'Optional reason for the pause'
271
+ }
272
+ },
273
+ required: ['duration']
274
+ };
275
+ }
276
+
277
+ /**
278
+ * Get tool capabilities metadata
279
+ * @returns {Object} Enhanced capabilities object
280
+ */
281
+ getCapabilities() {
282
+ const baseCapabilities = super.getCapabilities();
283
+
284
+ return {
285
+ ...baseCapabilities,
286
+ pauseRange: {
287
+ min: this.minPauseDuration,
288
+ max: this.maxPauseDuration,
289
+ unit: 'seconds'
290
+ },
291
+ affects: 'agent-status',
292
+ interactsWithAgentPool: true,
293
+ useCases: [
294
+ 'installation-waiting',
295
+ 'service-startup',
296
+ 'file-operations',
297
+ 'build-processes',
298
+ 'compilation',
299
+ 'deployment-delays'
300
+ ]
301
+ };
302
+ }
303
+
304
+ /**
305
+ * Format resume time for human readability
306
+ * @private
307
+ */
308
+ formatResumeTime(resumeDate) {
309
+ const now = new Date();
310
+ const diffSeconds = Math.round((resumeDate.getTime() - now.getTime()) / 1000);
311
+
312
+ if (diffSeconds < 60) {
313
+ return `in ${diffSeconds} second${diffSeconds !== 1 ? 's' : ''}`;
314
+ } else if (diffSeconds < 3600) {
315
+ const minutes = Math.round(diffSeconds / 60);
316
+ return `in ${minutes} minute${minutes !== 1 ? 's' : ''}`;
317
+ } else {
318
+ const hours = Math.round(diffSeconds / 3600);
319
+ return `in ${hours} hour${hours !== 1 ? 's' : ''}`;
320
+ }
321
+ }
322
+
323
+ /**
324
+ * Get usage examples for documentation
325
+ * @returns {Array<Object>} Array of usage examples
326
+ */
327
+ getUsageExamples() {
328
+ return [
329
+ {
330
+ title: 'Basic pause for 30 seconds',
331
+ command: `[tool id="agentdelay"]
332
+ <pause-duration>30</pause-duration>
333
+ [/tool]`,
334
+ description: 'Simple 30-second pause without specific reason'
335
+ },
336
+ {
337
+ title: 'Pause during package installation',
338
+ command: `[tool id="agentdelay"]
339
+ <pause-duration>120</pause-duration>
340
+ <reason>Waiting for npm install to complete</reason>
341
+ [/tool]`,
342
+ description: 'Pause for 2 minutes while packages are being installed'
343
+ },
344
+ {
345
+ title: 'Brief pause for service startup',
346
+ command: `[tool id="agentdelay"]
347
+ <pause-duration>45</pause-duration>
348
+ <reason>Allowing database service to start</reason>
349
+ [/tool]`,
350
+ description: 'Short pause to allow a service to fully initialize'
351
+ },
352
+ {
353
+ title: 'Extended pause for build process',
354
+ command: `[tool id="agentdelay"]
355
+ <pause-duration>300</pause-duration>
356
+ <reason>Waiting for large project compilation</reason>
357
+ [/tool]`,
358
+ description: 'Maximum duration pause for lengthy build operations'
359
+ }
360
+ ];
361
+ }
362
+
363
+ /**
364
+ * Check if agent can be paused
365
+ * @param {string} agentId - Agent identifier
366
+ * @returns {Promise<Object>} Check result
367
+ */
368
+ async canPauseAgent(agentId) {
369
+ if (!this.agentPool) {
370
+ return {
371
+ canPause: false,
372
+ reason: 'Agent pool not available'
373
+ };
374
+ }
375
+
376
+ try {
377
+ const agent = await this.agentPool.getAgent(agentId);
378
+
379
+ if (!agent) {
380
+ return {
381
+ canPause: false,
382
+ reason: 'Agent not found'
383
+ };
384
+ }
385
+
386
+ if (agent.status === AGENT_STATUS.PAUSED) {
387
+ return {
388
+ canPause: false,
389
+ reason: 'Agent is already paused',
390
+ pausedUntil: agent.pausedUntil
391
+ };
392
+ }
393
+
394
+ return {
395
+ canPause: true,
396
+ currentStatus: agent.status
397
+ };
398
+
399
+ } catch (error) {
400
+ return {
401
+ canPause: false,
402
+ reason: `Error checking agent status: ${error.message}`
403
+ };
404
+ }
405
+ }
406
+
407
+ /**
408
+ * Get pause recommendations based on context
409
+ * @param {Object} context - Execution context
410
+ * @returns {Object} Pause recommendations
411
+ */
412
+ getPauseRecommendations(context) {
413
+ const recommendations = {
414
+ suggested: [],
415
+ warnings: []
416
+ };
417
+
418
+ // Analyze context for pause suggestions
419
+ if (context.lastCommand && typeof context.lastCommand === 'string') {
420
+ const command = context.lastCommand.toLowerCase();
421
+
422
+ if (command.includes('npm install') || command.includes('yarn install')) {
423
+ recommendations.suggested.push({
424
+ duration: 90,
425
+ reason: 'Package installation typically takes 1-2 minutes',
426
+ confidence: 'high'
427
+ });
428
+ }
429
+
430
+ if (command.includes('docker build') || command.includes('docker run')) {
431
+ recommendations.suggested.push({
432
+ duration: 120,
433
+ reason: 'Docker operations often require extended time',
434
+ confidence: 'medium'
435
+ });
436
+ }
437
+
438
+ if (command.includes('make') || command.includes('build') || command.includes('compile')) {
439
+ recommendations.suggested.push({
440
+ duration: 180,
441
+ reason: 'Build/compilation processes can be time-intensive',
442
+ confidence: 'medium'
443
+ });
444
+ }
445
+
446
+ if (command.includes('git clone') || command.includes('git pull')) {
447
+ recommendations.suggested.push({
448
+ duration: 30,
449
+ reason: 'Git operations usually complete quickly',
450
+ confidence: 'high'
451
+ });
452
+ }
453
+ }
454
+
455
+ // Add warnings for very short or long pauses
456
+ if (context.requestedDuration) {
457
+ if (context.requestedDuration < 10) {
458
+ recommendations.warnings.push('Very short pauses may not be necessary');
459
+ }
460
+
461
+ if (context.requestedDuration > 240) {
462
+ recommendations.warnings.push('Consider if such a long pause is really needed');
463
+ }
464
+ }
465
+
466
+ return recommendations;
467
+ }
468
+
469
+ /**
470
+ * Enable/disable tool based on agent pool availability
471
+ * @param {Object} agentPool - Agent pool instance
472
+ */
473
+ setAgentPool(agentPool) {
474
+ this.agentPool = agentPool;
475
+ this.isEnabled = !!agentPool;
476
+
477
+ if (this.isEnabled) {
478
+ this.logger?.info('Agent delay tool enabled with agent pool');
479
+ } else {
480
+ this.logger?.warn('Agent delay tool disabled - no agent pool available');
481
+ }
482
+ }
483
+ }
484
+
485
+ export default AgentDelayTool;