wegho-agentes 4.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/.agents/AGENT_WORKFLOW.md +528 -0
- package/.agents/AI_COMPATIBILITY.md +332 -0
- package/.agents/CLI.md +222 -0
- package/.agents/README.md +130 -0
- package/.agents/cli.js +389 -0
- package/.agents/code-auditor-agent.ts +333 -0
- package/.agents/config.ts +145 -0
- package/.agents/context-loader.ts +300 -0
- package/.agents/core/agent-parallelizer.test.ts +94 -0
- package/.agents/core/agent-parallelizer.ts +108 -0
- package/.agents/core/architecture-agent.ts +237 -0
- package/.agents/core/base-agent.ts +311 -0
- package/.agents/core/cache-manager.test.ts +147 -0
- package/.agents/core/cache-manager.ts +184 -0
- package/.agents/core/documentation-agent.ts +183 -0
- package/.agents/core/feedback-collector.ts +207 -0
- package/.agents/core/frontend-agent.ts +210 -0
- package/.agents/core/inventory-agent.ts +582 -0
- package/.agents/core/memory-system.ts +397 -0
- package/.agents/core/quality-agent.ts +268 -0
- package/.agents/core/retry-utility.test.ts +165 -0
- package/.agents/core/retry-utility.ts +140 -0
- package/.agents/core/security-agent.ts +217 -0
- package/.agents/core/workflow-validator.test.ts +171 -0
- package/.agents/core/workflow-validator.ts +158 -0
- package/.agents/domains/README.md +53 -0
- package/.agents/domains/logistics/route-agent.ts +177 -0
- package/.agents/domains/news/cms-agent.ts +158 -0
- package/.agents/domains/news/seo-agent.ts +170 -0
- package/.agents/domains/production/production-control-agent.ts +169 -0
- package/.agents/example-learning-system.js +118 -0
- package/.agents/init.ts +164 -0
- package/.agents/memory/architecture-agent/failures.json +1 -0
- package/.agents/memory/architecture-agent/learnings.json +1 -0
- package/.agents/memory/architecture-agent/specialty.md +31 -0
- package/.agents/memory/architecture-agent/successes.json +16 -0
- package/.agents/memory/cms-agent/failures.json +1 -0
- package/.agents/memory/cms-agent/learnings.json +1 -0
- package/.agents/memory/cms-agent/specialty.md +30 -0
- package/.agents/memory/cms-agent/successes.json +16 -0
- package/.agents/memory/documentation-agent/failures.json +1 -0
- package/.agents/memory/documentation-agent/learnings.json +1 -0
- package/.agents/memory/documentation-agent/specialty.md +33 -0
- package/.agents/memory/documentation-agent/successes.json +16 -0
- package/.agents/memory/frontend-agent/failures.json +1 -0
- package/.agents/memory/frontend-agent/learnings.json +1 -0
- package/.agents/memory/frontend-agent/specialty.md +30 -0
- package/.agents/memory/frontend-agent/successes.json +16 -0
- package/.agents/memory/inventory-agent/failures.json +1 -0
- package/.agents/memory/inventory-agent/inventory/index.json +8 -0
- package/.agents/memory/inventory-agent/inventory/types.json +77716 -0
- package/.agents/memory/inventory-agent/inventory/variables.json +405 -0
- package/.agents/memory/inventory-agent/learnings.json +1 -0
- package/.agents/memory/inventory-agent/specialty.md +129 -0
- package/.agents/memory/inventory-agent/successes.json +30 -0
- package/.agents/memory/production-control-agent/failures.json +1 -0
- package/.agents/memory/production-control-agent/learnings.json +1 -0
- package/.agents/memory/production-control-agent/specialty.md +29 -0
- package/.agents/memory/production-control-agent/successes.json +16 -0
- package/.agents/memory/quality-agent/failures.json +16 -0
- package/.agents/memory/quality-agent/learnings.json +1 -0
- package/.agents/memory/quality-agent/specialty.md +31 -0
- package/.agents/memory/quality-agent/successes.json +1 -0
- package/.agents/memory/reference-repositories.json +271 -0
- package/.agents/memory/route-agent/failures.json +1 -0
- package/.agents/memory/route-agent/learnings.json +1 -0
- package/.agents/memory/route-agent/specialty.md +29 -0
- package/.agents/memory/route-agent/successes.json +16 -0
- package/.agents/memory/security-agent/failures.json +1 -0
- package/.agents/memory/security-agent/learnings.json +1 -0
- package/.agents/memory/security-agent/specialty.md +31 -0
- package/.agents/memory/security-agent/successes.json +16 -0
- package/.agents/memory/seo-agent/failures.json +1 -0
- package/.agents/memory/seo-agent/learnings.json +1 -0
- package/.agents/memory/seo-agent/specialty.md +31 -0
- package/.agents/memory/seo-agent/successes.json +16 -0
- package/.agents/orchestrator.ts +438 -0
- package/.agents/project-discovery-agent.ts +342 -0
- package/.agents/security/pentesting-agent.py +387 -0
- package/.agents/security/python-bridge.ts +193 -0
- package/.agents/security/vulnerability-db.json +201 -0
- package/.agents/task-analyzer-agent.ts +346 -0
- package/.agents/test-init-context.js +67 -0
- package/INSTALL.md +300 -0
- package/LICENSE +21 -0
- package/README.md +315 -0
- package/docs/AGENT_RULES.md +292 -0
- package/docs/BUILD_HISTORY.md +65 -0
- package/docs/DESIGN_SYSTEM.md +256 -0
- package/docs/LEARNING_SYSTEM.md +326 -0
- package/docs/SYMBOLS_TREE.md +182 -0
- package/docs/VERSION.md +6 -0
- package/docs/architecture.md +111 -0
- package/package.json +60 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Architecture Agent (com Memória)
|
|
3
|
+
*
|
|
4
|
+
* Responsabilidades:
|
|
5
|
+
* - Validar estrutura de arquivos
|
|
6
|
+
* - Garantir limite de 500 linhas por arquivo
|
|
7
|
+
* - Detectar duplicação de código
|
|
8
|
+
* - Validar separação de camadas
|
|
9
|
+
* - Aprender padrões arquiteturais que funcionam
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
import { BaseAgent, TaskContext, TaskResult } from './base-agent';
|
|
15
|
+
import { validateFileLines } from '../config';
|
|
16
|
+
|
|
17
|
+
export interface ArchitectureCheckResult extends TaskResult {
|
|
18
|
+
violations: Array<{
|
|
19
|
+
type: string;
|
|
20
|
+
file: string;
|
|
21
|
+
severity: 'error' | 'warning';
|
|
22
|
+
message: string;
|
|
23
|
+
suggestion: string;
|
|
24
|
+
}>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class ArchitectureAgent extends BaseAgent {
|
|
28
|
+
constructor(memoryBasePath: string = '.agents/memory') {
|
|
29
|
+
super('architecture-agent', memoryBasePath);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Implementação da validação arquitetural
|
|
34
|
+
*/
|
|
35
|
+
async executeTask(taskDescription: string, context: TaskContext): Promise<TaskResult> {
|
|
36
|
+
const violations: ArchitectureCheckResult['violations'] = [];
|
|
37
|
+
|
|
38
|
+
for (const filePath of context.files) {
|
|
39
|
+
if (!fs.existsSync(filePath)) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 1. Verificar limite de 500 linhas
|
|
44
|
+
const lineCheck = validateFileLines(filePath, 500);
|
|
45
|
+
if (!lineCheck.valid) {
|
|
46
|
+
violations.push({
|
|
47
|
+
type: 'file-too-long',
|
|
48
|
+
file: filePath,
|
|
49
|
+
severity: 'error',
|
|
50
|
+
message: `Arquivo tem ${lineCheck.lineCount} linhas (limite: 500)`,
|
|
51
|
+
suggestion: 'Refatorar: extrair funções, componentes ou classes para arquivos separados'
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
56
|
+
|
|
57
|
+
// 2. Detectar duplicação de código
|
|
58
|
+
const duplicates = this.detectCodeDuplication(content);
|
|
59
|
+
if (duplicates.length > 0) {
|
|
60
|
+
violations.push({
|
|
61
|
+
type: 'code-duplication',
|
|
62
|
+
file: filePath,
|
|
63
|
+
severity: 'warning',
|
|
64
|
+
message: `${duplicates.length} bloco(s) de código duplicado detectado(s)`,
|
|
65
|
+
suggestion: 'Extrair código duplicado para funções/componentes reutilizáveis'
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 3. Validar separação de camadas
|
|
70
|
+
const layerViolations = this.validateLayerSeparation(filePath, content);
|
|
71
|
+
violations.push(...layerViolations);
|
|
72
|
+
|
|
73
|
+
// 4. Verificar nomenclatura
|
|
74
|
+
const namingIssues = this.validateNaming(filePath);
|
|
75
|
+
violations.push(...namingIssues);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const errors = violations.filter(v => v.severity === 'error');
|
|
79
|
+
const success = errors.length === 0;
|
|
80
|
+
|
|
81
|
+
const details = this.formatViolations(violations);
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
success,
|
|
85
|
+
details,
|
|
86
|
+
issues: errors.map(v => v.message),
|
|
87
|
+
warnings: violations.filter(v => v.severity === 'warning').map(v => v.message),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Detecta duplicação de código
|
|
93
|
+
*/
|
|
94
|
+
private detectCodeDuplication(content: string): string[] {
|
|
95
|
+
const duplicates: string[] = [];
|
|
96
|
+
const lines = content.split('\n');
|
|
97
|
+
const blockSize = 5; // Mínimo de 5 linhas para considerar duplicação
|
|
98
|
+
|
|
99
|
+
// Algoritmo simplificado - em produção usaria algo como jscpd
|
|
100
|
+
const blocks = new Map<string, number>();
|
|
101
|
+
|
|
102
|
+
for (let i = 0; i <= lines.length - blockSize; i++) {
|
|
103
|
+
const block = lines.slice(i, i + blockSize).join('\n').trim();
|
|
104
|
+
if (block.length > 50) { // Ignorar blocos muito pequenos
|
|
105
|
+
const count = blocks.get(block) || 0;
|
|
106
|
+
blocks.set(block, count + 1);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
blocks.forEach((count, block) => {
|
|
111
|
+
if (count > 1) {
|
|
112
|
+
duplicates.push(block.substring(0, 100) + '...');
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
return duplicates;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Valida separação de camadas
|
|
121
|
+
*/
|
|
122
|
+
private validateLayerSeparation(filePath: string, content: string): ArchitectureCheckResult['violations'] {
|
|
123
|
+
const violations: ArchitectureCheckResult['violations'] = [];
|
|
124
|
+
|
|
125
|
+
// Componentes não devem ter lógica de API direta
|
|
126
|
+
if (filePath.includes('components/') && !filePath.includes('pages/')) {
|
|
127
|
+
if (content.match(/fetch\(|axios\.|supabase\./)) {
|
|
128
|
+
violations.push({
|
|
129
|
+
type: 'layer-violation',
|
|
130
|
+
file: filePath,
|
|
131
|
+
severity: 'warning',
|
|
132
|
+
message: 'Componente com chamada de API direta',
|
|
133
|
+
suggestion: 'Extrair lógica de API para hook customizado ou service'
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Utils não devem importar componentes
|
|
139
|
+
if (filePath.includes('utils/') || filePath.includes('lib/')) {
|
|
140
|
+
if (content.match(/import.*from.*components/)) {
|
|
141
|
+
violations.push({
|
|
142
|
+
type: 'layer-violation',
|
|
143
|
+
file: filePath,
|
|
144
|
+
severity: 'error',
|
|
145
|
+
message: 'Arquivo de utilidade importando componente',
|
|
146
|
+
suggestion: 'Utils devem ser independentes de componentes UI'
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return violations;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Valida nomenclatura de arquivos
|
|
156
|
+
*/
|
|
157
|
+
private validateNaming(filePath: string): ArchitectureCheckResult['violations'] {
|
|
158
|
+
const violations: ArchitectureCheckResult['violations'] = [];
|
|
159
|
+
const fileName = path.basename(filePath);
|
|
160
|
+
|
|
161
|
+
// Componentes React devem usar PascalCase
|
|
162
|
+
if (filePath.includes('components/') && fileName.match(/^[a-z]/)) {
|
|
163
|
+
violations.push({
|
|
164
|
+
type: 'naming-convention',
|
|
165
|
+
file: filePath,
|
|
166
|
+
severity: 'warning',
|
|
167
|
+
message: 'Componente deve usar PascalCase',
|
|
168
|
+
suggestion: `Renomear para ${fileName.charAt(0).toUpperCase() + fileName.slice(1)}`
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Hooks devem começar com 'use'
|
|
173
|
+
if (filePath.includes('hooks/') && !fileName.startsWith('use')) {
|
|
174
|
+
violations.push({
|
|
175
|
+
type: 'naming-convention',
|
|
176
|
+
file: filePath,
|
|
177
|
+
severity: 'warning',
|
|
178
|
+
message: 'Hook customizado deve começar com "use"',
|
|
179
|
+
suggestion: `Renomear para use${fileName.charAt(0).toUpperCase() + fileName.slice(1)}`
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return violations;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Formata violações
|
|
188
|
+
*/
|
|
189
|
+
private formatViolations(violations: ArchitectureCheckResult['violations']): string {
|
|
190
|
+
if (violations.length === 0) {
|
|
191
|
+
return 'Arquitetura validada com sucesso';
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const errors = violations.filter(v => v.severity === 'error').length;
|
|
195
|
+
const warnings = violations.filter(v => v.severity === 'warning').length;
|
|
196
|
+
|
|
197
|
+
return `Violações: ${errors} erro(s), ${warnings} aviso(s)`;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Especialidade padrão do Architecture Agent
|
|
202
|
+
*/
|
|
203
|
+
protected getDefaultSpecialty(): string {
|
|
204
|
+
return `# Architecture Agent - Especialidade
|
|
205
|
+
|
|
206
|
+
## Responsabilidades
|
|
207
|
+
- Validar estrutura de arquivos
|
|
208
|
+
- Garantir limite de 500 linhas por arquivo
|
|
209
|
+
- Detectar duplicação de código
|
|
210
|
+
- Validar separação de camadas (MVC, Clean Architecture)
|
|
211
|
+
- Verificar nomenclatura consistente
|
|
212
|
+
|
|
213
|
+
## Expertise
|
|
214
|
+
- Design Patterns (Factory, Strategy, Observer, etc.)
|
|
215
|
+
- SOLID Principles
|
|
216
|
+
- Clean Architecture
|
|
217
|
+
- Microservices Architecture
|
|
218
|
+
- Modularização e Componentização
|
|
219
|
+
- DRY (Don't Repeat Yourself)
|
|
220
|
+
|
|
221
|
+
## Regras
|
|
222
|
+
- Máximo 500 linhas por arquivo
|
|
223
|
+
- Sem duplicação de código (DRY)
|
|
224
|
+
- Separação clara de responsabilidades
|
|
225
|
+
- Nomenclatura consistente (PascalCase para componentes, camelCase para funções)
|
|
226
|
+
- Componentes UI não devem ter lógica de API
|
|
227
|
+
- Utils devem ser independentes de UI
|
|
228
|
+
|
|
229
|
+
## Tarefas Típicas
|
|
230
|
+
- Validar estrutura de novos componentes
|
|
231
|
+
- Detectar código duplicado
|
|
232
|
+
- Sugerir refatorações
|
|
233
|
+
- Validar separação de camadas
|
|
234
|
+
- Revisar nomenclatura de arquivos
|
|
235
|
+
`;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Agent - Classe base para todos os agentes
|
|
3
|
+
*
|
|
4
|
+
* Responsabilidades:
|
|
5
|
+
* - Fornecer interface comum para todos os agentes
|
|
6
|
+
* - Integrar sistema de memória
|
|
7
|
+
* - Gerenciar consulta e registro de resultados
|
|
8
|
+
* - Implementar aprendizado contínuo
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { MemorySystem, MemoryEntry } from './memory-system';
|
|
12
|
+
import { WorkflowStep } from './workflow-validator';
|
|
13
|
+
import * as fs from 'fs';
|
|
14
|
+
import * as path from 'path';
|
|
15
|
+
|
|
16
|
+
export interface TaskContext {
|
|
17
|
+
files: string[];
|
|
18
|
+
areas: string[];
|
|
19
|
+
complexity: 'low' | 'medium' | 'high';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface TaskResult {
|
|
23
|
+
success: boolean;
|
|
24
|
+
details: string;
|
|
25
|
+
issues?: string[];
|
|
26
|
+
warnings?: string[];
|
|
27
|
+
recommendations?: string[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface UserFeedback {
|
|
31
|
+
satisfied: boolean;
|
|
32
|
+
likes: string[];
|
|
33
|
+
dislikes: string[];
|
|
34
|
+
suggestions: string[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Classe base abstrata para agentes
|
|
39
|
+
*/
|
|
40
|
+
export abstract class BaseAgent {
|
|
41
|
+
protected agentName: string;
|
|
42
|
+
protected memory: MemorySystem;
|
|
43
|
+
protected specialtyPath: string;
|
|
44
|
+
protected workflowSteps: WorkflowStep[] = [];
|
|
45
|
+
protected referenceReposPath: string;
|
|
46
|
+
|
|
47
|
+
constructor(agentName: string, memoryBasePath: string = '.agents/memory') {
|
|
48
|
+
this.agentName = agentName;
|
|
49
|
+
this.memory = new MemorySystem(memoryBasePath);
|
|
50
|
+
this.specialtyPath = path.join(memoryBasePath, agentName, 'specialty.md');
|
|
51
|
+
this.referenceReposPath = path.join(memoryBasePath, 'reference-repositories.json');
|
|
52
|
+
this.ensureSpecialtyFile();
|
|
53
|
+
this.initializeWorkflowSteps();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Método abstrato: cada agente implementa sua lógica
|
|
58
|
+
*/
|
|
59
|
+
abstract executeTask(taskDescription: string, context: TaskContext): Promise<TaskResult>;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Executa tarefa consultando memória
|
|
63
|
+
*/
|
|
64
|
+
async executeWithMemory(taskDescription: string, context: TaskContext): Promise<TaskResult> {
|
|
65
|
+
console.log(`\n${'='.repeat(60)}`);
|
|
66
|
+
console.log(`🤖 AGENTE ATIVO: ${this.agentName.toUpperCase()}`);
|
|
67
|
+
console.log(`${'='.repeat(60)}`);
|
|
68
|
+
console.log(`📋 Tarefa: ${taskDescription}`);
|
|
69
|
+
console.log(`⏰ Início: ${new Date().toLocaleTimeString('pt-BR')}\n`);
|
|
70
|
+
|
|
71
|
+
// PASSO 1: Consultar casos similares
|
|
72
|
+
this.markStepCompleted('Consultar Memória', { count: 0 });
|
|
73
|
+
const similarCases = this.memory.getSimilarCases(this.agentName, taskDescription, 5);
|
|
74
|
+
|
|
75
|
+
if (similarCases.length > 0) {
|
|
76
|
+
console.log(`💭 [${this.agentName}] Encontrei ${similarCases.length} caso(s) similar(es):`);
|
|
77
|
+
similarCases.forEach((case_, index) => {
|
|
78
|
+
const emoji = case_.result === 'success' ? '✅' : '❌';
|
|
79
|
+
console.log(` ${index + 1}. ${emoji} ${case_.taskDescription}`);
|
|
80
|
+
if (case_.userFeedback) {
|
|
81
|
+
console.log(` Feedback: ${case_.userFeedback.satisfied ? '👍' : '👎'}`);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
this.updateStepDetails('Consultar Memória', { count: similarCases.length });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// PASSO 2: Obter recomendações baseadas em aprendizados
|
|
88
|
+
this.markStepCompleted('Obter Recomendações', { count: 0 });
|
|
89
|
+
const recommendations = this.memory.getRecommendations(this.agentName, taskDescription);
|
|
90
|
+
|
|
91
|
+
if (recommendations.length > 0) {
|
|
92
|
+
console.log(`\n💡 [${this.agentName}] Recomendações baseadas em aprendizados:`);
|
|
93
|
+
recommendations.forEach((rec, index) => {
|
|
94
|
+
console.log(` ${index + 1}. ${rec}`);
|
|
95
|
+
});
|
|
96
|
+
this.updateStepDetails('Obter Recomendações', { count: recommendations.length });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// PASSO 3: Consultar repositórios de referência
|
|
100
|
+
this.markStepCompleted('Consultar Repositórios');
|
|
101
|
+
await this.consultReferenceRepositories();
|
|
102
|
+
|
|
103
|
+
// PASSO 4: Aplicar aprendizados com alta confiança
|
|
104
|
+
this.markStepCompleted('Aplicar Aprendizados');
|
|
105
|
+
this.applyHighConfidenceLearnings(recommendations);
|
|
106
|
+
|
|
107
|
+
// Executar tarefa
|
|
108
|
+
console.log(`\n⚙️ [${this.agentName}] Executando tarefa...\n`);
|
|
109
|
+
const result = await this.executeTask(taskDescription, context);
|
|
110
|
+
|
|
111
|
+
// PASSO 5: Registrar resultado
|
|
112
|
+
this.markStepCompleted('Registrar Resultado');
|
|
113
|
+
await this.recordOutcome(taskDescription, context, result);
|
|
114
|
+
|
|
115
|
+
const status = result.success ? '✅ SUCESSO' : '❌ FALHA';
|
|
116
|
+
console.log(`\n${status} [${this.agentName}] Tarefa concluída`);
|
|
117
|
+
console.log(`⏰ Término: ${new Date().toLocaleTimeString('pt-BR')}`);
|
|
118
|
+
console.log(`${'='.repeat(60)}\n`);
|
|
119
|
+
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Registra resultado na memória
|
|
125
|
+
*/
|
|
126
|
+
async recordOutcome(
|
|
127
|
+
taskDescription: string,
|
|
128
|
+
context: TaskContext,
|
|
129
|
+
result: TaskResult,
|
|
130
|
+
userFeedback?: UserFeedback
|
|
131
|
+
): Promise<void> {
|
|
132
|
+
if (result.success) {
|
|
133
|
+
this.memory.recordSuccess(
|
|
134
|
+
this.agentName,
|
|
135
|
+
taskDescription,
|
|
136
|
+
context,
|
|
137
|
+
result.details,
|
|
138
|
+
userFeedback
|
|
139
|
+
);
|
|
140
|
+
} else {
|
|
141
|
+
this.memory.recordFailure(
|
|
142
|
+
this.agentName,
|
|
143
|
+
taskDescription,
|
|
144
|
+
context,
|
|
145
|
+
result.details,
|
|
146
|
+
userFeedback
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Adiciona aprendizado baseado em feedback
|
|
153
|
+
*/
|
|
154
|
+
async learn(
|
|
155
|
+
pattern: string,
|
|
156
|
+
description: string,
|
|
157
|
+
recommendation: string,
|
|
158
|
+
exampleIds: string[] = []
|
|
159
|
+
): Promise<void> {
|
|
160
|
+
this.memory.addLearning(
|
|
161
|
+
this.agentName,
|
|
162
|
+
pattern,
|
|
163
|
+
description,
|
|
164
|
+
recommendation,
|
|
165
|
+
exampleIds
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Obtém estatísticas do agente
|
|
171
|
+
*/
|
|
172
|
+
getStats() {
|
|
173
|
+
return this.memory.getStats(this.agentName);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Lê arquivo de especialidade
|
|
178
|
+
*/
|
|
179
|
+
getSpecialty(): string {
|
|
180
|
+
if (fs.existsSync(this.specialtyPath)) {
|
|
181
|
+
return fs.readFileSync(this.specialtyPath, 'utf-8');
|
|
182
|
+
}
|
|
183
|
+
return 'Especialidade não definida';
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Garante que arquivo de especialidade existe
|
|
188
|
+
*/
|
|
189
|
+
private ensureSpecialtyFile(): void {
|
|
190
|
+
const agentDir = path.dirname(this.specialtyPath);
|
|
191
|
+
|
|
192
|
+
if (!fs.existsSync(agentDir)) {
|
|
193
|
+
fs.mkdirSync(agentDir, { recursive: true });
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (!fs.existsSync(this.specialtyPath)) {
|
|
197
|
+
const defaultSpecialty = this.getDefaultSpecialty();
|
|
198
|
+
fs.writeFileSync(this.specialtyPath, defaultSpecialty, 'utf-8');
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Retorna especialidade padrão (pode ser sobrescrito)
|
|
204
|
+
*/
|
|
205
|
+
protected getDefaultSpecialty(): string {
|
|
206
|
+
return `# ${this.agentName} - Especialidade
|
|
207
|
+
|
|
208
|
+
## Responsabilidades
|
|
209
|
+
- Definir responsabilidades específicas
|
|
210
|
+
|
|
211
|
+
## Expertise
|
|
212
|
+
- Definir áreas de expertise
|
|
213
|
+
|
|
214
|
+
## Regras
|
|
215
|
+
- Definir regras específicas
|
|
216
|
+
|
|
217
|
+
## Tarefas Típicas
|
|
218
|
+
- Listar tarefas típicas
|
|
219
|
+
`;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Inicializa os passos do workflow
|
|
224
|
+
*/
|
|
225
|
+
private initializeWorkflowSteps(): void {
|
|
226
|
+
this.workflowSteps = [
|
|
227
|
+
{ name: 'Consultar Memória', required: true, completed: false },
|
|
228
|
+
{ name: 'Obter Recomendações', required: true, completed: false },
|
|
229
|
+
{ name: 'Consultar Repositórios', required: true, completed: false },
|
|
230
|
+
{ name: 'Aplicar Aprendizados', required: true, completed: false },
|
|
231
|
+
{ name: 'Registrar Resultado', required: true, completed: false },
|
|
232
|
+
{ name: 'Gerar Aprendizados', required: false, completed: false }
|
|
233
|
+
];
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Marca um passo como completado
|
|
238
|
+
*/
|
|
239
|
+
protected markStepCompleted(stepName: string, details?: any): void {
|
|
240
|
+
const step = this.workflowSteps.find(s => s.name === stepName);
|
|
241
|
+
if (step) {
|
|
242
|
+
step.completed = true;
|
|
243
|
+
step.timestamp = new Date();
|
|
244
|
+
step.details = details;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Atualiza detalhes de um passo
|
|
250
|
+
*/
|
|
251
|
+
protected updateStepDetails(stepName: string, details: any): void {
|
|
252
|
+
const step = this.workflowSteps.find(s => s.name === stepName);
|
|
253
|
+
if (step) {
|
|
254
|
+
step.details = { ...step.details, ...details };
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Retorna os passos do workflow para validação
|
|
260
|
+
*/
|
|
261
|
+
getWorkflowSteps(): WorkflowStep[] {
|
|
262
|
+
return [...this.workflowSteps];
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Consulta repositórios de referência relevantes
|
|
267
|
+
*/
|
|
268
|
+
protected async consultReferenceRepositories(): Promise<void> {
|
|
269
|
+
try {
|
|
270
|
+
if (!fs.existsSync(this.referenceReposPath)) {
|
|
271
|
+
console.log(`⚠️ [${this.agentName}] Arquivo de repositórios não encontrado`);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const repos = JSON.parse(fs.readFileSync(this.referenceReposPath, 'utf-8'));
|
|
276
|
+
const relevantRepos = this.getRelevantRepositories(repos);
|
|
277
|
+
|
|
278
|
+
if (relevantRepos.length > 0) {
|
|
279
|
+
console.log(`\n📚 [${this.agentName}] Consultando repositórios de referência:`);
|
|
280
|
+
relevantRepos.forEach(repo => {
|
|
281
|
+
console.log(` - ${repo.name}: ${repo.url}`);
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
} catch (error: any) {
|
|
285
|
+
console.log(`⚠️ [${this.agentName}] Erro ao consultar repositórios:`, error.message);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Retorna repositórios relevantes para este agente (pode ser sobrescrito)
|
|
291
|
+
*/
|
|
292
|
+
protected getRelevantRepositories(repos: any): Array<{ name: string; url: string }> {
|
|
293
|
+
// Implementação padrão - pode ser sobrescrita por agentes específicos
|
|
294
|
+
return [];
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Aplica aprendizados com alta confiança
|
|
299
|
+
*/
|
|
300
|
+
protected applyHighConfidenceLearnings(recommendations: string[]): void {
|
|
301
|
+
const memory = this.memory.loadMemory(this.agentName);
|
|
302
|
+
const highConfidenceLearnings = memory.learnings.filter(l => l.confidence > 0.7);
|
|
303
|
+
|
|
304
|
+
if (highConfidenceLearnings.length > 0) {
|
|
305
|
+
console.log(`\n🎯 [${this.agentName}] Aplicando ${highConfidenceLearnings.length} aprendizado(s) de alta confiança:`);
|
|
306
|
+
highConfidenceLearnings.forEach((learning, index) => {
|
|
307
|
+
console.log(` ${index + 1}. ${learning.recommendation} (confiança: ${(learning.confidence * 100).toFixed(0)}%)`);
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Testes para CacheManager
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { CacheManager } from './cache-manager';
|
|
6
|
+
|
|
7
|
+
describe('CacheManager', () => {
|
|
8
|
+
let cache: CacheManager;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
cache = new CacheManager(1000, 100); // 1s TTL, max 100 entries
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
cache.clear();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe('get and set', () => {
|
|
19
|
+
test('deve armazenar e recuperar valores', () => {
|
|
20
|
+
cache.set('key1', 'value1');
|
|
21
|
+
const result = cache.get<string>('key1');
|
|
22
|
+
|
|
23
|
+
expect(result).toBe('value1');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('deve retornar null para chave inexistente', () => {
|
|
27
|
+
const result = cache.get('nonexistent');
|
|
28
|
+
|
|
29
|
+
expect(result).toBeNull();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('deve expirar entradas após TTL', async () => {
|
|
33
|
+
cache.set('key1', 'value1', 100); // 100ms TTL
|
|
34
|
+
|
|
35
|
+
expect(cache.get('key1')).toBe('value1');
|
|
36
|
+
|
|
37
|
+
await new Promise(resolve => setTimeout(resolve, 150));
|
|
38
|
+
|
|
39
|
+
expect(cache.get('key1')).toBeNull();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('deve usar TTL customizado', async () => {
|
|
43
|
+
cache.set('key1', 'value1', 200); // 200ms TTL
|
|
44
|
+
|
|
45
|
+
await new Promise(resolve => setTimeout(resolve, 150));
|
|
46
|
+
expect(cache.get('key1')).toBe('value1'); // Ainda válido
|
|
47
|
+
|
|
48
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
49
|
+
expect(cache.get('key1')).toBeNull(); // Expirou
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe('statistics', () => {
|
|
54
|
+
test('deve rastrear hits e misses', () => {
|
|
55
|
+
cache.set('key1', 'value1');
|
|
56
|
+
|
|
57
|
+
cache.get('key1'); // hit
|
|
58
|
+
cache.get('key2'); // miss
|
|
59
|
+
cache.get('key1'); // hit
|
|
60
|
+
|
|
61
|
+
const stats = cache.getStats();
|
|
62
|
+
|
|
63
|
+
expect(stats.hits).toBe(2);
|
|
64
|
+
expect(stats.misses).toBe(1);
|
|
65
|
+
expect(stats.hitRate).toBeCloseTo(66.67, 1);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('deve resetar estatísticas', () => {
|
|
69
|
+
cache.set('key1', 'value1');
|
|
70
|
+
cache.get('key1');
|
|
71
|
+
cache.get('key2');
|
|
72
|
+
|
|
73
|
+
cache.resetStats();
|
|
74
|
+
const stats = cache.getStats();
|
|
75
|
+
|
|
76
|
+
expect(stats.hits).toBe(0);
|
|
77
|
+
expect(stats.misses).toBe(0);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('cleanup', () => {
|
|
82
|
+
test('deve remover entradas expiradas', async () => {
|
|
83
|
+
cache.set('key1', 'value1', 100);
|
|
84
|
+
cache.set('key2', 'value2', 1000);
|
|
85
|
+
|
|
86
|
+
await new Promise(resolve => setTimeout(resolve, 150));
|
|
87
|
+
|
|
88
|
+
const removed = cache.cleanup();
|
|
89
|
+
|
|
90
|
+
expect(removed).toBe(1);
|
|
91
|
+
expect(cache.size()).toBe(1);
|
|
92
|
+
expect(cache.get('key2')).toBe('value2');
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('LRU eviction', () => {
|
|
97
|
+
test('deve remover entrada menos usada quando atingir limite', () => {
|
|
98
|
+
const smallCache = new CacheManager(1000, 3);
|
|
99
|
+
|
|
100
|
+
smallCache.set('key1', 'value1');
|
|
101
|
+
smallCache.set('key2', 'value2');
|
|
102
|
+
smallCache.set('key3', 'value3');
|
|
103
|
+
|
|
104
|
+
// Acessar key1 e key2 para aumentar hits
|
|
105
|
+
smallCache.get('key1');
|
|
106
|
+
smallCache.get('key2');
|
|
107
|
+
|
|
108
|
+
// Adicionar key4 deve remover key3 (menos usada)
|
|
109
|
+
smallCache.set('key4', 'value4');
|
|
110
|
+
|
|
111
|
+
expect(smallCache.has('key3')).toBe(false);
|
|
112
|
+
expect(smallCache.has('key1')).toBe(true);
|
|
113
|
+
expect(smallCache.size()).toBe(3);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe('has', () => {
|
|
118
|
+
test('deve verificar existência de chave', () => {
|
|
119
|
+
cache.set('key1', 'value1');
|
|
120
|
+
|
|
121
|
+
expect(cache.has('key1')).toBe(true);
|
|
122
|
+
expect(cache.has('key2')).toBe(false);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test('deve retornar false para chave expirada', async () => {
|
|
126
|
+
cache.set('key1', 'value1', 100);
|
|
127
|
+
|
|
128
|
+
expect(cache.has('key1')).toBe(true);
|
|
129
|
+
|
|
130
|
+
await new Promise(resolve => setTimeout(resolve, 150));
|
|
131
|
+
|
|
132
|
+
expect(cache.has('key1')).toBe(false);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe('clear', () => {
|
|
137
|
+
test('deve limpar todo o cache', () => {
|
|
138
|
+
cache.set('key1', 'value1');
|
|
139
|
+
cache.set('key2', 'value2');
|
|
140
|
+
|
|
141
|
+
cache.clear();
|
|
142
|
+
|
|
143
|
+
expect(cache.size()).toBe(0);
|
|
144
|
+
expect(cache.get('key1')).toBeNull();
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
});
|