Files
Agentic-Compaction-and-Pipl…/delegation-system/pool/agent-pool-manager.ts
admin 8329636696 Add Delegation System with 3rd Party AI Tool Integration
NEW: Delegation System (v1.2.0)
- Request Classifier for fast request analysis (<50ms)
- Agent Pool Manager with auto-scaling (8 agent types)
- Delegation Engine with 4 strategies (full, parallel, hierarchical, hybrid)
- Progress Streamer for real-time updates
- Context Handoff Protocol for inter-agent communication
- Quality Gate with confidence thresholds and auto-escalation

NEW: 3rd Party Integration Adapters
- OpenClaw adapter with parallel execution support
- Claude Code CLI adapter with tool registration
- Generic adapter for custom integrations
- Standardized IntegrationAdapter interface

Agent Types Added:
- fast-responder (quick answers < 2s)
- explorer (code navigation)
- researcher (deep analysis)
- coder (implementation)
- reviewer (quality checks)
- planner (architecture)
- executor (commands)
- analyzer (debugging)

Tests: All 6 tests passing

This project was 100% autonomously built by Z.AI GLM-5
2026-03-04 10:06:17 +00:00

525 lines
14 KiB
TypeScript

/**
* Agent Pool Manager
*
* Manages a pool of subagents for delegation.
* Handles lifecycle, scaling, and task assignment.
*/
import {
PoolAgent,
AgentPoolConfig,
AgentStatus,
AgentType,
AgentSpawnConfig
} from '../core/types';
// ============================================================================
// Default Configuration
// ============================================================================
const DEFAULT_AGENT_CONFIGS: Record<AgentType, AgentSpawnConfig> = {
'fast-responder': {
type: 'fast-responder',
capabilities: ['quick-analysis', 'simple-tasks', 'status-checks'],
maxConcurrent: 10,
timeout: 5000,
retryAttempts: 1,
priority: 1
},
'explorer': {
type: 'explorer',
capabilities: ['code-navigation', 'file-search', 'pattern-matching'],
maxConcurrent: 4,
timeout: 30000,
retryAttempts: 2,
priority: 2
},
'researcher': {
type: 'researcher',
capabilities: ['deep-analysis', 'documentation', 'best-practices'],
maxConcurrent: 3,
timeout: 60000,
retryAttempts: 2,
priority: 3
},
'coder': {
type: 'coder',
capabilities: ['code-generation', 'implementation', 'modification'],
maxConcurrent: 4,
timeout: 45000,
retryAttempts: 2,
priority: 2
},
'reviewer': {
type: 'reviewer',
capabilities: ['code-review', 'quality-check', 'security-audit'],
maxConcurrent: 3,
timeout: 30000,
retryAttempts: 2,
priority: 2
},
'planner': {
type: 'planner',
capabilities: ['architecture', 'planning', 'decomposition'],
maxConcurrent: 2,
timeout: 60000,
retryAttempts: 1,
priority: 4
},
'executor': {
type: 'executor',
capabilities: ['command-execution', 'file-operations', 'safe-modification'],
maxConcurrent: 3,
timeout: 30000,
retryAttempts: 3,
priority: 1
},
'analyzer': {
type: 'analyzer',
capabilities: ['code-analysis', 'debugging', 'performance-profiling'],
maxConcurrent: 3,
timeout: 45000,
retryAttempts: 2,
priority: 2
}
};
const DEFAULT_POOL_CONFIG: AgentPoolConfig = {
maxSize: 50,
minIdle: 8, // At least 8 agents ready
warmUpTimeout: 5000,
coolDownPeriod: 10000,
scaleUpThreshold: 0.7, // Scale up when 70% are busy
scaleDownThreshold: 0.3, // Scale down when only 30% are busy
agentConfigs: DEFAULT_AGENT_CONFIGS
};
// ============================================================================
// Agent Pool Manager Class
// ============================================================================
export class AgentPoolManager {
private agents: Map<string, PoolAgent> = new Map();
private config: AgentPoolConfig;
private taskAssignments: Map<string, string> = new Map(); // taskId -> agentId
private scalingTimer?: NodeJS.Timeout;
private isShuttingDown: boolean = false;
constructor(config: Partial<AgentPoolConfig> = {}) {
this.config = { ...DEFAULT_POOL_CONFIG, ...config };
this.initializePool();
}
// ============================================================================
// Pool Initialization
// ============================================================================
private initializePool(): void {
// Create initial agents for each type
const initialCounts: Record<AgentType, number> = {
'fast-responder': 4, // More fast responders for quick tasks
'explorer': 2,
'researcher': 1,
'coder': 2,
'reviewer': 1,
'planner': 1,
'executor': 1,
'analyzer': 1
};
for (const [type, count] of Object.entries(initialCounts)) {
for (let i = 0; i < count; i++) {
this.spawnAgent(type as AgentType);
}
}
// Start scaling monitor
this.startScalingMonitor();
}
private spawnAgent(type: AgentType): PoolAgent | null {
if (this.agents.size >= this.config.maxSize) {
return null;
}
const config = this.config.agentConfigs[type];
if (!config) return null;
const agent: PoolAgent = {
id: this.generateAgentId(type),
type,
status: 'idle',
capabilities: config.capabilities,
completedTasks: 0,
averageResponseTime: 0,
successRate: 1.0,
createdAt: new Date()
};
this.agents.set(agent.id, agent);
return agent;
}
private generateAgentId(type: AgentType): string {
return `${type}-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`;
}
// ============================================================================
// Agent Selection
// ============================================================================
/**
* Get an available agent for a task
*/
acquireAgent(
type: AgentType,
requiredCapabilities?: string[],
taskId?: string
): PoolAgent | null {
// Find best matching idle agent
let bestAgent: PoolAgent | null = null;
let bestScore = -1;
for (const agent of this.agents.values()) {
if (agent.type !== type) continue;
if (agent.status !== 'idle') continue;
// Check capabilities
if (requiredCapabilities && requiredCapabilities.length > 0) {
const hasAllCapabilities = requiredCapabilities.every(
cap => agent.capabilities.includes(cap)
);
if (!hasAllCapabilities) continue;
}
// Score based on performance
const score = this.calculateAgentScore(agent);
if (score > bestScore) {
bestScore = score;
bestAgent = agent;
}
}
if (bestAgent) {
bestAgent.status = 'busy';
bestAgent.currentTask = taskId;
bestAgent.lastUsed = new Date();
if (taskId) {
this.taskAssignments.set(taskId, bestAgent.id);
}
}
return bestAgent;
}
/**
* Acquire multiple agents for parallel execution
*/
acquireAgents(
types: AgentType[],
taskId?: string
): PoolAgent[] {
const acquired: PoolAgent[] = [];
for (const type of types) {
const agent = this.acquireAgent(type, undefined, taskId);
if (agent) {
acquired.push(agent);
}
}
return acquired;
}
/**
* Release an agent back to the pool
*/
releaseAgent(agentId: string, result?: {
success: boolean;
responseTime: number;
}): void {
const agent = this.agents.get(agentId);
if (!agent) return;
agent.status = 'cooling-down';
agent.currentTask = undefined;
// Update stats
if (result) {
agent.completedTasks++;
agent.successRate = this.updateRunningAverage(
agent.successRate,
result.success ? 1 : 0,
agent.completedTasks
);
agent.averageResponseTime = this.updateRunningAverage(
agent.averageResponseTime,
result.responseTime,
agent.completedTasks
);
}
// Remove task assignment
for (const [taskId, aId] of this.taskAssignments) {
if (aId === agentId) {
this.taskAssignments.delete(taskId);
break;
}
}
// Schedule return to idle
setTimeout(() => {
if (this.agents.has(agentId) && !this.isShuttingDown) {
const a = this.agents.get(agentId);
if (a && a.status === 'cooling-down') {
a.status = 'idle';
}
}
}, this.config.coolDownPeriod);
}
private calculateAgentScore(agent: PoolAgent): number {
// Higher success rate = better
// Lower average response time = better
// More completed tasks = more reliable
const reliabilityScore = agent.successRate * 0.4;
const speedScore = (1 - Math.min(agent.averageResponseTime / 60000, 1)) * 0.3;
const experienceScore = Math.min(agent.completedTasks / 100, 1) * 0.3;
return reliabilityScore + speedScore + experienceScore;
}
private updateRunningAverage(current: number, newValue: number, count: number): number {
return current + (newValue - current) / count;
}
// ============================================================================
// Pool Scaling
// ============================================================================
private startScalingMonitor(): void {
this.scalingTimer = setInterval(() => {
this.checkScaling();
}, 5000);
}
private checkScaling(): void {
const stats = this.getPoolStats();
// Scale up if needed
if (stats.busyPercentage > this.config.scaleUpThreshold) {
this.scaleUp();
}
// Scale down if needed
if (stats.busyPercentage < this.config.scaleDownThreshold &&
stats.idleCount > this.config.minIdle * 2) {
this.scaleDown();
}
}
private scaleUp(): void {
// Find the type with most demand
const demandByType = this.getDemandByType();
let highestDemand: { type: AgentType; ratio: number } | null = null;
for (const [type, demand] of Object.entries(demandByType)) {
if (!highestDemand || demand.ratio > highestDemand.ratio) {
highestDemand = { type: type as AgentType, ratio: demand.ratio };
}
}
if (highestDemand && highestDemand.ratio > 0.5) {
this.spawnAgent(highestDemand.type);
}
}
private scaleDown(): void {
// Find idle agents that haven't been used recently
const now = Date.now();
const maxIdleTime = 5 * 60 * 1000; // 5 minutes
for (const [id, agent] of this.agents) {
if (agent.status !== 'idle') continue;
if (!agent.lastUsed) continue;
if (now - agent.lastUsed.getTime() > maxIdleTime) {
// Don't remove if it would go below minimum
if (this.getPoolStats().idleCount > this.config.minIdle) {
this.agents.delete(id);
break; // Only remove one at a time
}
}
}
}
private getDemandByType(): Record<string, { busy: number; idle: number; ratio: number }> {
const counts: Record<string, { busy: number; idle: number }> = {};
for (const agent of this.agents.values()) {
if (!counts[agent.type]) {
counts[agent.type] = { busy: 0, idle: 0 };
}
if (agent.status === 'busy') {
counts[agent.type].busy++;
} else if (agent.status === 'idle') {
counts[agent.type].idle++;
}
}
const result: Record<string, { busy: number; idle: number; ratio: number }> = {};
for (const [type, count] of Object.entries(counts)) {
const total = count.busy + count.idle;
result[type] = {
...count,
ratio: total > 0 ? count.busy / total : 0
};
}
return result;
}
// ============================================================================
// Pool Statistics
// ============================================================================
getPoolStats(): {
total: number;
idleCount: number;
busyCount: number;
coolingDownCount: number;
busyPercentage: number;
availablePercentage: number;
byType: Record<AgentType, { total: number; idle: number; busy: number }>;
} {
let idleCount = 0;
let busyCount = 0;
let coolingDownCount = 0;
const byType: Record<AgentType, { total: number; idle: number; busy: number }> = {} as any;
for (const agent of this.agents.values()) {
// Initialize type stats
if (!byType[agent.type]) {
byType[agent.type] = { total: 0, idle: 0, busy: 0 };
}
byType[agent.type].total++;
switch (agent.status) {
case 'idle':
idleCount++;
byType[agent.type].idle++;
break;
case 'busy':
busyCount++;
byType[agent.type].busy++;
break;
case 'cooling-down':
coolingDownCount++;
break;
}
}
const total = this.agents.size;
return {
total,
idleCount,
busyCount,
coolingDownCount,
busyPercentage: total > 0 ? busyCount / total : 0,
availablePercentage: total > 0 ? (idleCount + coolingDownCount) / total : 0,
byType
};
}
/**
* Check if pool has available agents
*/
hasAvailableAgent(type: AgentType): boolean {
for (const agent of this.agents.values()) {
if (agent.type === type && agent.status === 'idle') {
return true;
}
}
return false;
}
/**
* Get available agent count by type
*/
getAvailableCount(type: AgentType): number {
let count = 0;
for (const agent of this.agents.values()) {
if (agent.type === type && agent.status === 'idle') {
count++;
}
}
return count;
}
// ============================================================================
// Task Tracking
// ============================================================================
getAgentByTask(taskId: string): PoolAgent | undefined {
const agentId = this.taskAssignments.get(taskId);
if (agentId) {
return this.agents.get(agentId);
}
return undefined;
}
// ============================================================================
// Lifecycle
// ============================================================================
/**
* Shutdown the pool
*/
async shutdown(): Promise<void> {
this.isShuttingDown = true;
if (this.scalingTimer) {
clearInterval(this.scalingTimer);
}
// Wait for busy agents to complete (with timeout)
const maxWait = 30000;
const startTime = Date.now();
while (Date.now() - startTime < maxWait) {
const stats = this.getPoolStats();
if (stats.busyCount === 0) break;
await this.sleep(1000);
}
this.agents.clear();
this.taskAssignments.clear();
}
private sleep(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* Get all agents (for debugging/monitoring)
*/
getAllAgents(): PoolAgent[] {
return Array.from(this.agents.values());
}
}
// ============================================================================
// Factory Function
// ============================================================================
export function createAgentPoolManager(config?: Partial<AgentPoolConfig>): AgentPoolManager {
return new AgentPoolManager(config);
}
// ============================================================================
// Export
// ============================================================================
export default AgentPoolManager;