93 lines
3.1 KiB
JavaScript
93 lines
3.1 KiB
JavaScript
// ==============================|| Doormile AI — Autonomous Agent Factory ||============================== //
|
|
import { SkillRegistry } from '../skills/SkillRegistry';
|
|
import { wallClockNow } from './signals';
|
|
|
|
const SEVERITY_RANK = { critical: 0, warning: 1, watch: 2 };
|
|
|
|
export class AgentFactory {
|
|
/**
|
|
* Compiles an Agent configuration from a collection of skills.
|
|
*/
|
|
static createAgent(skills = SkillRegistry.getActiveSkills()) {
|
|
const activeSkills = Array.isArray(skills) ? skills : [];
|
|
|
|
// 1. Synthesize System Prompt
|
|
const instructions = activeSkills
|
|
.map((s) => `### ${s.name} (${s.category})\n${(s.instructions || '').trim()}`)
|
|
.join('\n\n');
|
|
|
|
const systemPrompt = `
|
|
You are the Doormile Autonomous Logistics Fleet Orchestrator.
|
|
You operate with the following active operational skill modules:
|
|
|
|
${instructions || 'Standard logistics routing and telemetry diagnostics.'}
|
|
|
|
Guiding Invariant:
|
|
Read-only queries execute instantly. Mutating actions (reassignments, pings, OTP enforcement) MUST return human-in-the-loop proposals with clear blast radius.
|
|
`.trim();
|
|
|
|
// 2. Aggregate Tools from active skills
|
|
const tools = activeSkills.flatMap((s) => s.tools || []);
|
|
const toolMap = new Map();
|
|
tools.forEach((t) => toolMap.set(t.name, t));
|
|
|
|
// 3. Telemetry Evaluation Engine
|
|
const evaluateTelemetry = (rows = [], now = wallClockNow()) => {
|
|
const allFindings = [];
|
|
|
|
for (const skill of activeSkills) {
|
|
if (typeof skill.evaluate === 'function') {
|
|
// Extract current threshold values
|
|
const rawThresholds = {};
|
|
if (skill.effectiveThresholds) {
|
|
Object.entries(skill.effectiveThresholds).forEach(([k, v]) => {
|
|
rawThresholds[k] = v.currentValue;
|
|
});
|
|
} else if (skill.thresholds) {
|
|
Object.entries(skill.thresholds).forEach(([k, v]) => {
|
|
rawThresholds[k] = v.value;
|
|
});
|
|
}
|
|
|
|
const findings = skill.evaluate(rows, now, rawThresholds);
|
|
if (Array.isArray(findings)) {
|
|
allFindings.push(...findings);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sort by severity (critical > warning > watch), then by affected row count descending
|
|
return allFindings.sort(
|
|
(a, b) =>
|
|
(SEVERITY_RANK[a.severity] ?? 99) - (SEVERITY_RANK[b.severity] ?? 99) ||
|
|
(b.count || 0) - (a.count || 0)
|
|
);
|
|
};
|
|
|
|
return {
|
|
name: 'Doormile Fleet Orchestrator',
|
|
version: '2.0.0',
|
|
activeSkillCount: activeSkills.length,
|
|
skills: activeSkills,
|
|
tools,
|
|
toolMap,
|
|
systemPrompt,
|
|
evaluateTelemetry,
|
|
executeSkillTool: async (toolName, args) => {
|
|
const tool = toolMap.get(toolName);
|
|
if (!tool || typeof tool.handler !== 'function') {
|
|
return { success: false, error: `Skill tool "${toolName}" not found or has no handler.` };
|
|
}
|
|
return tool.handler(args);
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Helper to build the default active agent runtime based on current SkillRegistry state.
|
|
*/
|
|
static synthesizeDefaultAgent() {
|
|
return AgentFactory.createAgent(SkillRegistry.getActiveSkills());
|
|
}
|
|
}
|