feat: massive Ruflo-inspired upgrade — plugin system, multi-agent swarm, hooks, enhanced memory
New systems (src/plugins/): - Plugin.js: lifecycle hooks (onLoad, onUnload, onConfigChange) + BasePlugin - PluginManager.js: fault-isolated extension point dispatch with metrics - PluginLoader.js: dependency-resolving batch loader with health checks - ExtensionPoints.js: 16 standard extension point names New systems (src/bot/): - hooks.js: HookManager with pre/post tool, pre/post AI, session lifecycle - memory-backend.js: JSONBackend (typed entries + LRU) + InMemoryBackend (ephemeral with TTL) New systems (src/agents/): - Agent.js: typed agents with capabilities, status tracking - Task.js: DAG-compatible tasks with priorities, dependencies, rollback - SwarmCoordinator.js: multi-agent orchestration (simple/hierarchical/swarm topologies) - agents/index.js: 9 agent roles + AgentOrchestrator Bot integration (src/bot/index.js): - 6 new Ruflo-inspired tools: swarm_spawn, swarm_execute, swarm_distribute, swarm_state, swarm_terminate - Plugin system, hook system, swarm initialized in initBot - Pre/post tool hooks wired into tool execution - Ephemeral + persistent memory backends - Agent orchestrator with 9 specialized agent types - Graceful shutdown: all systems cleanup, conversation flush, pidfile release - Return object exposes pluginManager, swarm, hookManager, memBackend, agentOrchestrator, getState This brings Ruflo's multi-agent architecture, plugin extensibility, hook-based lifecycle, and typed memory to zCode.
This commit is contained in:
106
src/agents/Agent.js
Normal file
106
src/agents/Agent.js
Normal file
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* zCode Agent Model — Ported from Ruflo Agent.ts
|
||||
* Individual agent with capabilities, status, task execution.
|
||||
*/
|
||||
|
||||
/** @typedef {'coder'|'tester'|'reviewer'|'architect'|'coordinator'|'designer'|'deployer'|'researcher'|'security'} AgentType */
|
||||
/** @typedef {'idle'|'active'|'busy'|'error'} AgentStatus */
|
||||
|
||||
let _agentCounter = 0;
|
||||
const _id = () => `agent_${Date.now().toString(36)}_${++_agentCounter}`;
|
||||
|
||||
export class Agent {
|
||||
/**
|
||||
* @param {Object} config
|
||||
* @param {string} [config.id]
|
||||
* @param {AgentType} config.type
|
||||
* @param {string} config.name
|
||||
* @param {string} [config.description]
|
||||
* @param {string[]} [config.capabilities]
|
||||
* @param {string} [config.role]
|
||||
* @param {Object} [config.metadata]
|
||||
*/
|
||||
constructor(config) {
|
||||
this.id = config.id || _id();
|
||||
this.type = config.type || 'coder';
|
||||
this.name = config.name || this.type;
|
||||
this.description = config.description || '';
|
||||
this.status = 'idle';
|
||||
this.capabilities = config.capabilities || [];
|
||||
this.role = config.role || null;
|
||||
this.parent = config.parent || null;
|
||||
this.metadata = config.metadata || {};
|
||||
this.createdAt = Date.now();
|
||||
this.lastActive = Date.now();
|
||||
this._taskCount = 0;
|
||||
this._errorCount = 0;
|
||||
this._conversationContext = null;
|
||||
}
|
||||
|
||||
get idle() { return this.status === 'idle'; }
|
||||
get active() { return this.status === 'active' || this.status === 'busy'; }
|
||||
|
||||
/** Execute a task */
|
||||
async executeTask(task) {
|
||||
this.status = 'busy';
|
||||
this.lastActive = Date.now();
|
||||
this._taskCount++;
|
||||
|
||||
try {
|
||||
const result = typeof task.execute === 'function'
|
||||
? await task.execute(this)
|
||||
: { status: 'completed', output: null };
|
||||
this.status = 'idle';
|
||||
return result;
|
||||
} catch (err) {
|
||||
this._errorCount++;
|
||||
this.status = 'error';
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/** Check if agent has a specific capability */
|
||||
hasCapability(cap) {
|
||||
return this.capabilities.some(c => c.toLowerCase() === cap.toLowerCase());
|
||||
}
|
||||
|
||||
/** Check if agent can handle a task based on capabilities */
|
||||
canHandleTask(task) {
|
||||
if (!task.requiredCapabilities || task.requiredCapabilities.length === 0) return true;
|
||||
return task.requiredCapabilities.some(c => this.hasCapability(c));
|
||||
}
|
||||
|
||||
/** Set agent's conversation context */
|
||||
setContext(ctx) { this._conversationContext = ctx; }
|
||||
getContext() { return this._conversationContext; }
|
||||
|
||||
/** Add extra context to conversation */
|
||||
addContext(key, value) {
|
||||
if (!this._conversationContext) this._conversationContext = {};
|
||||
this._conversationContext[key] = value;
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
id: this.id,
|
||||
type: this.type,
|
||||
name: this.name,
|
||||
description: this.description,
|
||||
status: this.status,
|
||||
capabilities: this.capabilities,
|
||||
role: this.role,
|
||||
parent: this.parent,
|
||||
taskCount: this._taskCount,
|
||||
errorCount: this._errorCount,
|
||||
createdAt: this.createdAt,
|
||||
lastActive: this.lastActive,
|
||||
};
|
||||
}
|
||||
|
||||
/** Create an agent from a config object (deserialization) */
|
||||
static fromConfig(config) {
|
||||
return new Agent(config);
|
||||
}
|
||||
}
|
||||
|
||||
export default Agent;
|
||||
Reference in New Issue
Block a user