188 lines
5.9 KiB
TypeScript
188 lines
5.9 KiB
TypeScript
/**
|
|
* Arcadia Suite - Generator Agent
|
|
*
|
|
* Agente responsável por gerar código a partir de especificações.
|
|
* Lê arquivos existentes para manter consistência.
|
|
*
|
|
* @author Arcadia Development Team
|
|
* @version 2.0.0
|
|
*/
|
|
|
|
import { BaseBlackboardAgent, type AgentConfig } from "../BaseBlackboardAgent";
|
|
import { blackboardService } from "../service";
|
|
import { type BlackboardTask } from "@shared/schema";
|
|
import { toolManager } from "../../autonomous/tools";
|
|
|
|
const SYSTEM_PROMPT = `Você é o Agente Gerador de Código do Arcadia Suite.
|
|
|
|
## Seu Papel
|
|
Você gera código TypeScript/React de alta qualidade baseado em especificações técnicas.
|
|
Você pode ler arquivos existentes para manter consistência de estilo.
|
|
|
|
## Stack do Arcadia Suite
|
|
- Backend: Node.js, Express, TypeScript
|
|
- Frontend: React 18, TypeScript, Tailwind CSS, shadcn/ui
|
|
- Banco: PostgreSQL com Drizzle ORM
|
|
- Autenticação: Passport.js com sessões
|
|
- Estado: TanStack Query (React Query)
|
|
|
|
## Padrões de Código
|
|
1. Sempre use TypeScript com tipos estritos
|
|
2. Use componentes funcionais com hooks
|
|
3. Siga o padrão existente de rotas Express
|
|
4. Use Drizzle ORM para queries
|
|
5. Use shadcn/ui para componentes de UI
|
|
6. Adicione data-testid em elementos interativos
|
|
|
|
## Formato de Saída
|
|
Para cada arquivo, retorne JSON:
|
|
{
|
|
"files": [
|
|
{
|
|
"path": "caminho/completo/arquivo.ts",
|
|
"content": "código completo do arquivo",
|
|
"type": "schema|route|component|hook|util",
|
|
"action": "create|modify"
|
|
}
|
|
]
|
|
}`;
|
|
|
|
export class GeneratorAgent extends BaseBlackboardAgent {
|
|
constructor() {
|
|
const config: AgentConfig = {
|
|
name: "generator",
|
|
displayName: "Agente Gerador de Código",
|
|
description: "Gera código TypeScript/React a partir de especificações",
|
|
systemPrompt: SYSTEM_PROMPT,
|
|
capabilities: [
|
|
"Geração de schemas Drizzle",
|
|
"Criação de rotas Express",
|
|
"Componentes React/TypeScript",
|
|
"Leitura de código existente",
|
|
"Manutenção de consistência"
|
|
],
|
|
pollInterval: 2000
|
|
};
|
|
super(config);
|
|
}
|
|
|
|
canHandle(task: BlackboardTask): boolean {
|
|
const context = task.context as any;
|
|
return context?.phase === "codegen" || task.assignedAgent === "generator";
|
|
}
|
|
|
|
async process(task: BlackboardTask): Promise<void> {
|
|
await this.log(task.id, "thinking", "Buscando especificação e contexto...");
|
|
|
|
const specArtifact = await blackboardService.getLatestArtifact(task.id, "spec");
|
|
const contextArtifact = await blackboardService.getLatestArtifact(task.id, "doc");
|
|
|
|
if (!specArtifact) {
|
|
await blackboardService.failTask(task.id, "generator", "Especificação não encontrada");
|
|
return;
|
|
}
|
|
|
|
let spec: any;
|
|
try {
|
|
spec = JSON.parse(specArtifact.content || "{}");
|
|
} catch {
|
|
spec = { raw: specArtifact.content };
|
|
}
|
|
|
|
await this.log(task.id, "reading", "Lendo arquivos de referência...");
|
|
|
|
let schemaRef = "";
|
|
const schemaResult = await toolManager.execute("read_file", { path: "shared/schema.ts", startLine: 1, endLine: 100 });
|
|
if (schemaResult.success) {
|
|
schemaRef = `\nREFERÊNCIA - shared/schema.ts (primeiras 100 linhas):\n\`\`\`typescript\n${schemaResult.data?.content?.slice(0, 2000)}\n\`\`\``;
|
|
}
|
|
|
|
let routesRef = "";
|
|
const routesResult = await toolManager.execute("read_file", { path: "server/routes.ts", startLine: 1, endLine: 50 });
|
|
if (routesResult.success) {
|
|
routesRef = `\nREFERÊNCIA - server/routes.ts (primeiras 50 linhas):\n\`\`\`typescript\n${routesResult.data?.content?.slice(0, 1500)}\n\`\`\``;
|
|
}
|
|
|
|
await this.log(task.id, "generating", "Gerando código baseado na especificação...");
|
|
|
|
const prompt = `Com base nesta especificação, gere o código completo:
|
|
|
|
ESPECIFICAÇÃO:
|
|
${JSON.stringify(spec, null, 2)}
|
|
|
|
CONTEXTO DO PROJETO:
|
|
${contextArtifact?.content?.slice(0, 2000) || "Não disponível"}
|
|
|
|
${schemaRef}
|
|
${routesRef}
|
|
|
|
Gere arquivos completos e funcionais para:
|
|
1. Schema do banco de dados (se necessário) - adicionar ao shared/schema.ts
|
|
2. Rotas da API - novo arquivo em server/ ou adicionar a routes.ts
|
|
3. Componente principal React - em client/src/pages/
|
|
|
|
Retorne em formato JSON com a estrutura:
|
|
{
|
|
"files": [
|
|
{ "path": "caminho/completo.ts", "content": "código completo", "type": "tipo", "action": "create|modify" }
|
|
]
|
|
}
|
|
|
|
IMPORTANTE: Gere código completo e funcional, não use placeholders ou "// TODO".`;
|
|
|
|
try {
|
|
const response = await this.generateWithAI(prompt);
|
|
|
|
let files: any[] = [];
|
|
try {
|
|
const jsonMatch = response.match(/\{[\s\S]*\}/);
|
|
if (jsonMatch) {
|
|
const parsed = JSON.parse(jsonMatch[0]);
|
|
files = parsed.files || [];
|
|
}
|
|
} catch {
|
|
files = [{
|
|
path: `server/modules/${spec.moduleName || "generated"}/index.ts`,
|
|
content: response,
|
|
type: "module",
|
|
action: "create"
|
|
}];
|
|
}
|
|
|
|
for (const file of files) {
|
|
await blackboardService.addArtifact(
|
|
task.id,
|
|
"code",
|
|
file.path,
|
|
file.content,
|
|
"generator",
|
|
{ type: file.type, action: file.action }
|
|
);
|
|
}
|
|
|
|
await this.log(task.id, "completed", `Gerados ${files.length} arquivos`);
|
|
|
|
const mainTask = await blackboardService.getMainTask(task.id);
|
|
if (mainTask) {
|
|
await blackboardService.createSubtask(
|
|
mainTask.id,
|
|
"Validar código",
|
|
"Validar e testar o código gerado",
|
|
"validator",
|
|
[task.id],
|
|
{ phase: "validation" }
|
|
);
|
|
}
|
|
|
|
await blackboardService.completeTask(task.id, "generator", {
|
|
filesGenerated: files.length,
|
|
files: files.map(f => ({ path: f.path, type: f.type, action: f.action })),
|
|
});
|
|
} catch (error: any) {
|
|
await blackboardService.failTask(task.id, "generator", error.message);
|
|
}
|
|
}
|
|
}
|
|
|
|
export const generatorAgent = new GeneratorAgent();
|