arcadiasuite/server/blackboard/BaseBlackboardAgent.ts

190 lines
5.6 KiB
TypeScript

/**
* Arcadia Suite - Base Blackboard Agent
*
* Classe base para agentes que monitoram e reagem ao Blackboard.
*
* @author Arcadia Development Team
* @version 1.0.0
*/
import OpenAI from "openai";
import { blackboardService, type AgentName, type TaskStatus } from "./service";
import { type BlackboardTask, type BlackboardArtifact } from "@shared/schema";
import { EventEmitter } from "events";
import { governanceService } from "../governance/service";
const openai = new OpenAI({
apiKey: process.env.AI_INTEGRATIONS_OPENAI_API_KEY,
baseURL: process.env.AI_INTEGRATIONS_OPENAI_BASE_URL,
});
export interface AgentConfig {
name: AgentName;
displayName: string;
description: string;
systemPrompt: string;
capabilities: string[];
pollInterval?: number;
}
export interface AgentThought {
thought: string;
action?: string;
actionInput?: any;
finished?: boolean;
result?: any;
}
export abstract class BaseBlackboardAgent extends EventEmitter {
protected config: AgentConfig;
protected isRunning: boolean = false;
protected pollTimer: NodeJS.Timeout | null = null;
constructor(config: AgentConfig) {
super();
this.config = config;
}
get name(): AgentName {
return this.config.name;
}
get displayName(): string {
return this.config.displayName;
}
abstract canHandle(task: BlackboardTask): boolean;
abstract process(task: BlackboardTask): Promise<void>;
protected async think(
task: BlackboardTask,
context: string,
artifacts: BlackboardArtifact[] = []
): Promise<AgentThought> {
const artifactContext = artifacts.length > 0
? `\n\nArtefatos disponíveis:\n${artifacts.map(a => `- ${a.name} (${a.type}): ${a.content?.slice(0, 500)}...`).join('\n')}`
: '';
try {
const response = await openai.chat.completions.create({
model: "gpt-4o-mini",
messages: [
{ role: "system", content: this.config.systemPrompt },
{
role: "user",
content: `TAREFA: ${task.title}\n\nDESCRIÇÃO: ${task.description}\n\nCONTEXTO: ${context}${artifactContext}\n\nResponda em JSON: { "thought": "seu raciocínio", "action": "próxima ação", "actionInput": {}, "finished": true/false, "result": "se finished=true" }`
}
],
response_format: { type: "json_object" },
max_tokens: 4000,
});
const content = response.choices[0]?.message?.content || '{}';
return JSON.parse(content) as AgentThought;
} catch (error: any) {
console.error(`[${this.name}] Erro ao pensar:`, error.message);
return {
thought: `Erro ao processar: ${error.message}`,
finished: true,
result: { error: error.message }
};
}
}
protected async generateWithAI(prompt: string, systemPrompt?: string): Promise<string> {
try {
const response = await openai.chat.completions.create({
model: "gpt-4o-mini",
messages: [
{ role: "system", content: systemPrompt || this.config.systemPrompt },
{ role: "user", content: prompt }
],
max_tokens: 8000,
});
return response.choices[0]?.message?.content || '';
} catch (error: any) {
console.error(`[${this.name}] Erro na geração:`, error.message);
throw error;
}
}
protected async log(taskId: number, action: string, thought: string, observation?: string): Promise<void> {
await blackboardService.logAction(taskId, this.name, action, thought, observation);
console.log(`[${this.name}] ${action}: ${thought}`);
await governanceService.recordAudit({
agentName: this.name,
action,
target: thought.slice(0, 200),
decision: "logged",
justification: observation?.slice(0, 500),
taskId,
});
}
protected async checkPolicy(action: string, target: string, context?: any): Promise<boolean> {
const evaluation = await governanceService.evaluatePolicy(this.name, action, target, context);
if (!evaluation.allowed) {
console.warn(`[${this.name}] Ação bloqueada pela governança: ${evaluation.reason}`);
}
return evaluation.allowed;
}
async start(): Promise<void> {
if (this.isRunning) return;
this.isRunning = true;
console.log(`[${this.name}] Agente iniciado`);
this.poll();
}
private async poll(): Promise<void> {
if (!this.isRunning) return;
try {
const tasks = await blackboardService.getPendingTasksForAgent(this.name);
for (const task of tasks) {
if (this.canHandle(task)) {
const claimed = await blackboardService.claimTask(task.id, this.name);
if (claimed) {
console.log(`[${this.name}] Processando tarefa: ${task.title}`);
try {
await this.process(task);
} catch (error: any) {
console.error(`[${this.name}] Erro ao processar tarefa:`, error.message);
await blackboardService.failTask(task.id, this.name, error.message);
}
}
}
}
} catch (error: any) {
console.error(`[${this.name}] Erro no polling:`, error.message);
}
this.pollTimer = setTimeout(() => this.poll(), this.config.pollInterval || 2000);
}
stop(): void {
this.isRunning = false;
if (this.pollTimer) {
clearTimeout(this.pollTimer);
this.pollTimer = null;
}
console.log(`[${this.name}] Agente parado`);
}
getStatus(): { name: string; running: boolean; capabilities: string[] } {
return {
name: this.displayName,
running: this.isRunning,
capabilities: this.config.capabilities,
};
}
}