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
This commit is contained in:
642
delegation-system/core/delegation-engine.ts
Normal file
642
delegation-system/core/delegation-engine.ts
Normal file
@@ -0,0 +1,642 @@
|
||||
/**
|
||||
* Delegation Engine
|
||||
*
|
||||
* Makes intelligent decisions about when and how to delegate requests.
|
||||
* Routes requests to appropriate agents based on classification and pool state.
|
||||
*/
|
||||
|
||||
import {
|
||||
DelegationDecision,
|
||||
DelegationStrategy,
|
||||
DelegationContext,
|
||||
DelegationResult,
|
||||
RequestClassification,
|
||||
ClassifiableRequest,
|
||||
AgentType,
|
||||
PoolAgent
|
||||
} from '../core/types';
|
||||
import { RequestClassifier } from '../core/request-classifier';
|
||||
import { AgentPoolManager } from '../pool/agent-pool-manager';
|
||||
|
||||
// ============================================================================
|
||||
// Delegation Configuration
|
||||
// ============================================================================
|
||||
|
||||
interface DelegationConfig {
|
||||
// Main agent load thresholds
|
||||
mainAgentBusyThreshold: number; // 0-1, above this = delegate
|
||||
mainAgentQueueThreshold: number; // max queue before delegation
|
||||
|
||||
// Delegation preferences
|
||||
preferDelegation: boolean;
|
||||
maxDelegationTime: number; // ms before fallback
|
||||
parallelThreshold: number; // complexity score for parallel delegation
|
||||
|
||||
// Fallback settings
|
||||
fallbackToMain: boolean;
|
||||
escalationEnabled: boolean;
|
||||
escalationThreshold: number; // confidence below this triggers escalation
|
||||
}
|
||||
|
||||
const DEFAULT_CONFIG: DelegationConfig = {
|
||||
mainAgentBusyThreshold: 0.7,
|
||||
mainAgentQueueThreshold: 5,
|
||||
preferDelegation: true,
|
||||
maxDelegationTime: 60000,
|
||||
parallelThreshold: 0.6,
|
||||
fallbackToMain: true,
|
||||
escalationEnabled: true,
|
||||
escalationThreshold: 0.7
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Main Agent State (simulated)
|
||||
// ============================================================================
|
||||
|
||||
interface MainAgentState {
|
||||
load: number; // 0-1
|
||||
queueLength: number;
|
||||
currentTask?: string;
|
||||
averageResponseTime: number;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Delegation Engine Class
|
||||
// ============================================================================
|
||||
|
||||
export class DelegationEngine {
|
||||
private config: DelegationConfig;
|
||||
private classifier: RequestClassifier;
|
||||
private poolManager: AgentPoolManager;
|
||||
private mainAgentState: MainAgentState;
|
||||
private activeDelegations: Map<string, DelegationContext> = new Map();
|
||||
private delegationHistory: DelegationContext[] = [];
|
||||
private maxHistorySize: number = 1000;
|
||||
|
||||
constructor(
|
||||
classifier: RequestClassifier,
|
||||
poolManager: AgentPoolManager,
|
||||
config: Partial<DelegationConfig> = {}
|
||||
) {
|
||||
this.config = { ...DEFAULT_CONFIG, ...config };
|
||||
this.classifier = classifier;
|
||||
this.poolManager = poolManager;
|
||||
this.mainAgentState = {
|
||||
load: 0,
|
||||
queueLength: 0,
|
||||
averageResponseTime: 5000
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Delegation Decision
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Make a delegation decision for a request
|
||||
*/
|
||||
async makeDecision(
|
||||
request: ClassifiableRequest,
|
||||
classification?: RequestClassification
|
||||
): Promise<DelegationDecision> {
|
||||
// Classify if not provided
|
||||
if (!classification) {
|
||||
classification = await this.classifier.classify(request);
|
||||
}
|
||||
|
||||
// Get current state
|
||||
const poolStats = this.poolManager.getPoolStats();
|
||||
|
||||
// Decision tree
|
||||
const decision = this.evaluateDelegation(request, classification, poolStats);
|
||||
|
||||
return decision;
|
||||
}
|
||||
|
||||
private evaluateDelegation(
|
||||
request: ClassifiableRequest,
|
||||
classification: RequestClassification,
|
||||
poolStats: ReturnType<AgentPoolManager['getPoolStats']>
|
||||
): DelegationDecision {
|
||||
const mainAgentLoad = this.mainAgentState.load;
|
||||
const mainAgentQueue = this.mainAgentState.queueLength;
|
||||
|
||||
// Check if can delegate
|
||||
if (!classification.canDelegate) {
|
||||
return this.noDelegation(classification, 'Request cannot be delegated');
|
||||
}
|
||||
|
||||
// Check if pool has available agents
|
||||
if (poolStats.idleCount === 0 && poolStats.coolingDownCount === 0) {
|
||||
if (this.config.fallbackToMain) {
|
||||
return this.noDelegation(classification, 'No agents available in pool');
|
||||
}
|
||||
return this.queueDelegation(classification, 'Waiting for agent availability');
|
||||
}
|
||||
|
||||
// Main agent is lightly loaded - process directly
|
||||
if (mainAgentLoad < 0.5 && mainAgentQueue < 3) {
|
||||
if (!this.config.preferDelegation || classification.complexity === 'complex') {
|
||||
return this.noDelegation(classification, 'Main agent available');
|
||||
}
|
||||
}
|
||||
|
||||
// Determine delegation strategy
|
||||
const strategy = this.determineStrategy(classification, poolStats);
|
||||
const targetAgents = this.selectAgents(classification, strategy, poolStats);
|
||||
const estimatedCompletion = this.estimateCompletion(classification, strategy, poolStats);
|
||||
|
||||
return {
|
||||
shouldDelegate: true,
|
||||
strategy,
|
||||
targetAgents,
|
||||
estimatedCompletion,
|
||||
reason: this.getDelegationReason(mainAgentLoad, poolStats),
|
||||
fallbackPlan: this.config.fallbackToMain ? 'main-agent' : 'queue',
|
||||
requiresCallback: strategy === 'hierarchical' || classification.complexity === 'complex'
|
||||
};
|
||||
}
|
||||
|
||||
private determineStrategy(
|
||||
classification: RequestClassification,
|
||||
poolStats: ReturnType<AgentPoolManager['getPoolStats']>
|
||||
): DelegationStrategy {
|
||||
// Complex requests with high confidence -> hierarchical
|
||||
if (classification.complexity === 'complex' && classification.confidence > 0.8) {
|
||||
return 'hierarchical';
|
||||
}
|
||||
|
||||
// Multiple files or high complexity score -> parallel
|
||||
if (classification.contextRequirements.files > 2 ||
|
||||
classification.score > this.config.parallelThreshold) {
|
||||
if (poolStats.idleCount >= 2) {
|
||||
return 'parallel';
|
||||
}
|
||||
}
|
||||
|
||||
// Quick requests -> full delegation
|
||||
if (classification.complexity === 'quick') {
|
||||
return 'full';
|
||||
}
|
||||
|
||||
// Streaming requests with progress -> hybrid
|
||||
if (classification.complexity === 'streaming') {
|
||||
return 'hybrid';
|
||||
}
|
||||
|
||||
// Default to full delegation
|
||||
return 'full';
|
||||
}
|
||||
|
||||
private selectAgents(
|
||||
classification: RequestClassification,
|
||||
strategy: DelegationStrategy,
|
||||
poolStats: ReturnType<AgentPoolManager['getPoolStats']>
|
||||
): AgentType[] {
|
||||
const primary = classification.recommendedAgent;
|
||||
const agents: AgentType[] = [];
|
||||
|
||||
switch (strategy) {
|
||||
case 'full':
|
||||
agents.push(primary);
|
||||
break;
|
||||
|
||||
case 'parallel':
|
||||
// Add primary agent and complementary agents
|
||||
agents.push(primary);
|
||||
if (classification.requiredCapabilities.includes('security')) {
|
||||
agents.push('reviewer');
|
||||
}
|
||||
if (classification.contextRequirements.files > 3) {
|
||||
agents.push('explorer');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'hierarchical':
|
||||
// Planner oversees execution
|
||||
agents.push('planner', primary);
|
||||
if (classification.requiredCapabilities.includes('security')) {
|
||||
agents.push('reviewer');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'hybrid':
|
||||
agents.push(primary);
|
||||
// Add support agents if available
|
||||
if (poolStats.idleCount > 2) {
|
||||
agents.push('fast-responder');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return agents;
|
||||
}
|
||||
|
||||
private estimateCompletion(
|
||||
classification: RequestClassification,
|
||||
strategy: DelegationStrategy,
|
||||
poolStats: ReturnType<AgentPoolManager['getPoolStats']>
|
||||
): number {
|
||||
let baseTime = classification.estimatedTime;
|
||||
|
||||
// Adjust for strategy
|
||||
switch (strategy) {
|
||||
case 'parallel':
|
||||
// Parallel is faster but has coordination overhead
|
||||
baseTime = baseTime * 0.6 + 500;
|
||||
break;
|
||||
case 'hierarchical':
|
||||
// Hierarchical has communication overhead
|
||||
baseTime = baseTime * 1.3;
|
||||
break;
|
||||
case 'hybrid':
|
||||
baseTime = baseTime * 0.8;
|
||||
break;
|
||||
}
|
||||
|
||||
// Adjust for pool availability
|
||||
const availabilityFactor = 1 + (1 - poolStats.availablePercentage) * 0.5;
|
||||
|
||||
return Math.round(baseTime * availabilityFactor);
|
||||
}
|
||||
|
||||
private getDelegationReason(
|
||||
mainAgentLoad: number,
|
||||
poolStats: ReturnType<AgentPoolManager['getPoolStats']>
|
||||
): string {
|
||||
if (mainAgentLoad > 0.8) {
|
||||
return 'Main agent at high capacity';
|
||||
}
|
||||
if (poolStats.busyPercentage > 0.7) {
|
||||
return 'Optimal for parallel processing';
|
||||
}
|
||||
return 'Fast delegation path available';
|
||||
}
|
||||
|
||||
private noDelegation(classification: RequestClassification, reason: string): DelegationDecision {
|
||||
return {
|
||||
shouldDelegate: false,
|
||||
strategy: 'full',
|
||||
targetAgents: [classification.recommendedAgent],
|
||||
estimatedCompletion: classification.estimatedTime,
|
||||
reason,
|
||||
requiresCallback: false
|
||||
};
|
||||
}
|
||||
|
||||
private queueDelegation(classification: RequestClassification, reason: string): DelegationDecision {
|
||||
return {
|
||||
shouldDelegate: true,
|
||||
strategy: 'full',
|
||||
targetAgents: [classification.recommendedAgent],
|
||||
estimatedCompletion: classification.estimatedTime + 10000, // Add queue time
|
||||
reason,
|
||||
fallbackPlan: 'queue',
|
||||
requiresCallback: true
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Delegation Execution
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Execute a delegation
|
||||
*/
|
||||
async executeDelegation(
|
||||
request: ClassifiableRequest,
|
||||
decision: DelegationDecision,
|
||||
executor: (agentType: AgentType, agentId: string, request: ClassifiableRequest) => Promise<any>
|
||||
): Promise<DelegationResult> {
|
||||
const requestId = this.generateRequestId();
|
||||
const startTime = Date.now();
|
||||
|
||||
// Create delegation context
|
||||
const context: DelegationContext = {
|
||||
requestId,
|
||||
originalRequest: request,
|
||||
classification: await this.classifier.classify(request),
|
||||
delegationDecision: decision,
|
||||
assignedAgents: [],
|
||||
status: 'in-progress',
|
||||
startTime: new Date()
|
||||
};
|
||||
|
||||
this.activeDelegations.set(requestId, context);
|
||||
|
||||
try {
|
||||
let result: any;
|
||||
const agentsUsed: string[] = [];
|
||||
|
||||
switch (decision.strategy) {
|
||||
case 'full':
|
||||
result = await this.executeFull(request, decision, executor, agentsUsed);
|
||||
break;
|
||||
case 'parallel':
|
||||
result = await this.executeParallel(request, decision, executor, agentsUsed);
|
||||
break;
|
||||
case 'hierarchical':
|
||||
result = await this.executeHierarchical(request, decision, executor, agentsUsed);
|
||||
break;
|
||||
case 'hybrid':
|
||||
result = await this.executeHybrid(request, decision, executor, agentsUsed);
|
||||
break;
|
||||
}
|
||||
|
||||
const delegationResult: DelegationResult = {
|
||||
success: true,
|
||||
output: result.output || result,
|
||||
confidence: result.confidence || 0.9,
|
||||
tokensUsed: result.tokensUsed || 0,
|
||||
duration: Date.now() - startTime,
|
||||
agentsUsed,
|
||||
needsReview: context.classification.complexity === 'complex'
|
||||
};
|
||||
|
||||
context.status = 'completed';
|
||||
context.endTime = new Date();
|
||||
context.result = delegationResult;
|
||||
|
||||
this.addToHistory(context);
|
||||
return delegationResult;
|
||||
|
||||
} catch (error) {
|
||||
const delegationResult: DelegationResult = {
|
||||
success: false,
|
||||
output: `Delegation failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
confidence: 0,
|
||||
tokensUsed: 0,
|
||||
duration: Date.now() - startTime,
|
||||
agentsUsed: [],
|
||||
needsReview: true,
|
||||
escalationReason: error instanceof Error ? error.message : 'Unknown error'
|
||||
};
|
||||
|
||||
context.status = 'failed';
|
||||
context.endTime = new Date();
|
||||
context.result = delegationResult;
|
||||
|
||||
this.addToHistory(context);
|
||||
return delegationResult;
|
||||
} finally {
|
||||
this.activeDelegations.delete(requestId);
|
||||
}
|
||||
}
|
||||
|
||||
private async executeFull(
|
||||
request: ClassifiableRequest,
|
||||
decision: DelegationDecision,
|
||||
executor: (agentType: AgentType, agentId: string, request: ClassifiableRequest) => Promise<any>,
|
||||
agentsUsed: string[]
|
||||
): Promise<any> {
|
||||
const agentType = decision.targetAgents[0];
|
||||
const agent = this.poolManager.acquireAgent(agentType, undefined, request.content.slice(0, 50));
|
||||
|
||||
if (!agent) {
|
||||
throw new Error(`No ${agentType} agent available`);
|
||||
}
|
||||
|
||||
agentsUsed.push(agent.id);
|
||||
|
||||
try {
|
||||
const result = await executor(agentType, agent.id, request);
|
||||
return result;
|
||||
} finally {
|
||||
this.poolManager.releaseAgent(agent.id);
|
||||
}
|
||||
}
|
||||
|
||||
private async executeParallel(
|
||||
request: ClassifiableRequest,
|
||||
decision: DelegationDecision,
|
||||
executor: (agentType: AgentType, agentId: string, request: ClassifiableRequest) => Promise<any>,
|
||||
agentsUsed: string[]
|
||||
): Promise<any> {
|
||||
const agents = this.poolManager.acquireAgents(decision.targetAgents, request.content.slice(0, 50));
|
||||
|
||||
if (agents.length === 0) {
|
||||
throw new Error('No agents available for parallel execution');
|
||||
}
|
||||
|
||||
agents.forEach(a => agentsUsed.push(a.id));
|
||||
|
||||
// Split request for parallel execution
|
||||
const subRequests = this.splitRequest(request, agents.length);
|
||||
|
||||
try {
|
||||
const results = await Promise.all(
|
||||
agents.map((agent, i) => executor(agent.type, agent.id, subRequests[i] || request))
|
||||
);
|
||||
|
||||
// Merge results
|
||||
return this.mergeResults(results);
|
||||
} finally {
|
||||
agents.forEach(a => this.poolManager.releaseAgent(a.id));
|
||||
}
|
||||
}
|
||||
|
||||
private async executeHierarchical(
|
||||
request: ClassifiableRequest,
|
||||
decision: DelegationDecision,
|
||||
executor: (agentType: AgentType, agentId: string, request: ClassifiableRequest) => Promise<any>,
|
||||
agentsUsed: string[]
|
||||
): Promise<any> {
|
||||
// First, planner creates plan
|
||||
const plannerAgent = this.poolManager.acquireAgent('planner', undefined, request.content.slice(0, 50));
|
||||
|
||||
if (!plannerAgent) {
|
||||
return this.executeFull(request, decision, executor, agentsUsed);
|
||||
}
|
||||
|
||||
agentsUsed.push(plannerAgent.id);
|
||||
|
||||
try {
|
||||
// Get plan from planner
|
||||
const plan = await executor('planner', plannerAgent.id, {
|
||||
...request,
|
||||
content: `Create execution plan for: ${request.content}`
|
||||
});
|
||||
|
||||
// Execute plan steps with primary agent
|
||||
const primaryType = decision.targetAgents[decision.targetAgents.indexOf('planner') + 1] || 'coder';
|
||||
const primaryAgent = this.poolManager.acquireAgent(primaryType);
|
||||
|
||||
if (primaryAgent) {
|
||||
agentsUsed.push(primaryAgent.id);
|
||||
const result = await executor(primaryType, primaryAgent.id, {
|
||||
...request,
|
||||
content: `Execute this plan:\n${plan.output}\n\nOriginal request: ${request.content}`
|
||||
});
|
||||
|
||||
this.poolManager.releaseAgent(primaryAgent.id);
|
||||
return result;
|
||||
}
|
||||
|
||||
return plan;
|
||||
} finally {
|
||||
this.poolManager.releaseAgent(plannerAgent.id);
|
||||
}
|
||||
}
|
||||
|
||||
private async executeHybrid(
|
||||
request: ClassifiableRequest,
|
||||
decision: DelegationDecision,
|
||||
executor: (agentType: AgentType, agentId: string, request: ClassifiableRequest) => Promise<any>,
|
||||
agentsUsed: string[]
|
||||
): Promise<any> {
|
||||
// Start with fast response, then enhance
|
||||
const fastAgent = this.poolManager.acquireAgent('fast-responder');
|
||||
|
||||
if (fastAgent) {
|
||||
agentsUsed.push(fastAgent.id);
|
||||
|
||||
try {
|
||||
// Quick initial response
|
||||
const quickResult = await executor('fast-responder', fastAgent.id, request);
|
||||
|
||||
// Enhanced processing with primary agent
|
||||
const primaryType = decision.targetAgents[0];
|
||||
const primaryAgent = this.poolManager.acquireAgent(primaryType);
|
||||
|
||||
if (primaryAgent) {
|
||||
agentsUsed.push(primaryAgent.id);
|
||||
|
||||
const enhancedResult = await executor(primaryType, primaryAgent.id, {
|
||||
...request,
|
||||
content: `Enhance this response:\n${quickResult.output}\n\nOriginal: ${request.content}`
|
||||
});
|
||||
|
||||
this.poolManager.releaseAgent(primaryAgent.id);
|
||||
return enhancedResult;
|
||||
}
|
||||
|
||||
return quickResult;
|
||||
} finally {
|
||||
this.poolManager.releaseAgent(fastAgent.id);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to full delegation
|
||||
return this.executeFull(request, decision, executor, agentsUsed);
|
||||
}
|
||||
|
||||
private splitRequest(request: ClassifiableRequest, parts: number): ClassifiableRequest[] {
|
||||
// Simple splitting by files if available
|
||||
if (request.files && request.files.length >= parts) {
|
||||
const filesPerPart = Math.ceil(request.files.length / parts);
|
||||
return Array.from({ length: parts }, (_, i) => ({
|
||||
...request,
|
||||
files: request.files?.slice(i * filesPerPart, (i + 1) * filesPerPart)
|
||||
}));
|
||||
}
|
||||
|
||||
// Otherwise return the same request for each agent
|
||||
return Array(parts).fill(request);
|
||||
}
|
||||
|
||||
private mergeResults(results: any[]): any {
|
||||
if (results.length === 1) return results[0];
|
||||
|
||||
return {
|
||||
output: results.map(r => r.output || r).join('\n\n---\n\n'),
|
||||
confidence: results.reduce((sum, r) => sum + (r.confidence || 0.9), 0) / results.length,
|
||||
tokensUsed: results.reduce((sum, r) => sum + (r.tokensUsed || 0), 0)
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main Agent State Management
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Update main agent state (called by integration layer)
|
||||
*/
|
||||
updateMainAgentState(state: Partial<MainAgentState>): void {
|
||||
this.mainAgentState = { ...this.mainAgentState, ...state };
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current main agent state
|
||||
*/
|
||||
getMainAgentState(): MainAgentState {
|
||||
return { ...this.mainAgentState };
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// History and Monitoring
|
||||
// ============================================================================
|
||||
|
||||
private addToHistory(context: DelegationContext): void {
|
||||
this.delegationHistory.push(context);
|
||||
|
||||
if (this.delegationHistory.length > this.maxHistorySize) {
|
||||
this.delegationHistory.shift();
|
||||
}
|
||||
}
|
||||
|
||||
getActiveDelegations(): DelegationContext[] {
|
||||
return Array.from(this.activeDelegations.values());
|
||||
}
|
||||
|
||||
getDelegationHistory(limit: number = 100): DelegationContext[] {
|
||||
return this.delegationHistory.slice(-limit);
|
||||
}
|
||||
|
||||
getStats(): {
|
||||
totalDelegations: number;
|
||||
successfulDelegations: number;
|
||||
failedDelegations: number;
|
||||
averageDuration: number;
|
||||
strategyUsage: Record<DelegationStrategy, number>;
|
||||
} {
|
||||
const history = this.delegationHistory;
|
||||
|
||||
const stats = {
|
||||
totalDelegations: history.length,
|
||||
successfulDelegations: history.filter(h => h.status === 'completed').length,
|
||||
failedDelegations: history.filter(h => h.status === 'failed').length,
|
||||
averageDuration: 0,
|
||||
strategyUsage: {
|
||||
full: 0,
|
||||
parallel: 0,
|
||||
hierarchical: 0,
|
||||
hybrid: 0
|
||||
} as Record<DelegationStrategy, number>
|
||||
};
|
||||
|
||||
if (history.length > 0) {
|
||||
const durations = history
|
||||
.filter(h => h.result)
|
||||
.map(h => h.result!.duration);
|
||||
stats.averageDuration = durations.reduce((a, b) => a + b, 0) / durations.length || 0;
|
||||
|
||||
history.forEach(h => {
|
||||
stats.strategyUsage[h.delegationDecision.strategy]++;
|
||||
});
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
private generateRequestId(): string {
|
||||
return `del-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Factory Function
|
||||
// ============================================================================
|
||||
|
||||
export function createDelegationEngine(
|
||||
classifier: RequestClassifier,
|
||||
poolManager: AgentPoolManager,
|
||||
config?: Partial<DelegationConfig>
|
||||
): DelegationEngine {
|
||||
return new DelegationEngine(classifier, poolManager, config);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Export
|
||||
// ============================================================================
|
||||
|
||||
export default DelegationEngine;
|
||||
Reference in New Issue
Block a user