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:
370
delegation-system/core/context-handoff.ts
Normal file
370
delegation-system/core/context-handoff.ts
Normal file
@@ -0,0 +1,370 @@
|
||||
/**
|
||||
* Context Handoff Protocol
|
||||
*
|
||||
* Manages context transfer between agents for seamless delegation.
|
||||
* Ensures proper serialization, validation, and cleanup of handoffs.
|
||||
*/
|
||||
|
||||
import {
|
||||
ContextHandoff,
|
||||
HandoffResult,
|
||||
ConversationTurn,
|
||||
DelegationContext
|
||||
} from '../core/types';
|
||||
|
||||
// ============================================================================
|
||||
// Handoff Configuration
|
||||
// ============================================================================
|
||||
|
||||
interface HandoffConfig {
|
||||
defaultTimeout: number;
|
||||
defaultTimeLimit: number;
|
||||
maxHandoffs: number;
|
||||
cleanupInterval: number;
|
||||
handoffTTL: number;
|
||||
}
|
||||
|
||||
const DEFAULT_CONFIG: HandoffConfig = {
|
||||
defaultTimeout: 30000,
|
||||
defaultTimeLimit: 60000,
|
||||
maxHandoffs: 100,
|
||||
cleanupInterval: 60000,
|
||||
handoffTTL: 300000 // 5 minutes
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Context Handoff Manager Class
|
||||
// ============================================================================
|
||||
|
||||
export class ContextHandoffManager {
|
||||
private config: HandoffConfig;
|
||||
private activeHandoffs: Map<string, ContextHandoff> = new Map();
|
||||
private completedHandoffs: Map<string, HandoffResult> = new Map();
|
||||
private cleanupTimer?: NodeJS.Timeout;
|
||||
private handoffCounter: number = 0;
|
||||
|
||||
constructor(config: Partial<HandoffConfig> = {}) {
|
||||
this.config = { ...DEFAULT_CONFIG, ...config };
|
||||
this.startCleanupTimer();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Handoff Creation
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Create a new context handoff
|
||||
*/
|
||||
createHandoff(options: {
|
||||
sourceAgent: string;
|
||||
targetAgent: string;
|
||||
request: any;
|
||||
files?: Record<string, string>;
|
||||
conversationHistory?: ConversationTurn[];
|
||||
workspace?: string;
|
||||
metadata?: Record<string, any>;
|
||||
timeLimit?: number;
|
||||
scope?: 'narrow' | 'medium' | 'broad';
|
||||
qualityLevel?: 'fast' | 'balanced' | 'thorough';
|
||||
callbackEndpoint?: string;
|
||||
callbackTimeout?: number;
|
||||
}): ContextHandoff {
|
||||
const id = this.generateHandoffId();
|
||||
|
||||
const handoff: ContextHandoff = {
|
||||
id,
|
||||
sourceAgent: options.sourceAgent,
|
||||
targetAgent: options.targetAgent,
|
||||
request: options.request,
|
||||
context: {
|
||||
files: options.files || {},
|
||||
conversationHistory: options.conversationHistory || [],
|
||||
workspace: options.workspace || '',
|
||||
metadata: options.metadata || {}
|
||||
},
|
||||
constraints: {
|
||||
timeLimit: options.timeLimit || this.config.defaultTimeLimit,
|
||||
scope: options.scope || 'medium',
|
||||
qualityLevel: options.qualityLevel || 'balanced'
|
||||
},
|
||||
callback: {
|
||||
endpoint: options.callbackEndpoint || '',
|
||||
timeout: options.callbackTimeout || this.config.defaultTimeout,
|
||||
retries: 3
|
||||
},
|
||||
createdAt: new Date(),
|
||||
expiresAt: new Date(Date.now() + this.config.handoffTTL)
|
||||
};
|
||||
|
||||
this.activeHandoffs.set(id, handoff);
|
||||
this.handoffCounter++;
|
||||
|
||||
return handoff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create handoff from delegation context
|
||||
*/
|
||||
createFromDelegation(
|
||||
delegationContext: DelegationContext,
|
||||
sourceAgent: string,
|
||||
targetAgent: string
|
||||
): ContextHandoff {
|
||||
return this.createHandoff({
|
||||
sourceAgent,
|
||||
targetAgent,
|
||||
request: delegationContext.originalRequest,
|
||||
metadata: {
|
||||
requestId: delegationContext.requestId,
|
||||
classification: delegationContext.classification,
|
||||
strategy: delegationContext.delegationDecision.strategy
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Handoff Execution
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Get a handoff by ID
|
||||
*/
|
||||
getHandoff(id: string): ContextHandoff | undefined {
|
||||
return this.activeHandoffs.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete a handoff with result
|
||||
*/
|
||||
completeHandoff(
|
||||
handoffId: string,
|
||||
result: {
|
||||
success: boolean;
|
||||
output?: any;
|
||||
error?: string;
|
||||
processingTime: number;
|
||||
}
|
||||
): HandoffResult {
|
||||
const handoff = this.activeHandoffs.get(handoffId);
|
||||
|
||||
const handoffResult: HandoffResult = {
|
||||
handoffId,
|
||||
success: result.success,
|
||||
result: result.output,
|
||||
error: result.error,
|
||||
processingTime: result.processingTime
|
||||
};
|
||||
|
||||
// Store result
|
||||
this.completedHandoffs.set(handoffId, handoffResult);
|
||||
|
||||
// Remove from active
|
||||
if (handoff) {
|
||||
this.activeHandoffs.delete(handoffId);
|
||||
|
||||
// Execute callback if configured
|
||||
if (handoff.callback.endpoint) {
|
||||
this.executeCallback(handoff, handoffResult);
|
||||
}
|
||||
}
|
||||
|
||||
return handoffResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel a handoff
|
||||
*/
|
||||
cancelHandoff(handoffId: string, reason: string): void {
|
||||
const handoff = this.activeHandoffs.get(handoffId);
|
||||
|
||||
if (handoff) {
|
||||
this.completeHandoff(handoffId, {
|
||||
success: false,
|
||||
error: `Cancelled: ${reason}`,
|
||||
processingTime: 0
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Callback Execution
|
||||
// ============================================================================
|
||||
|
||||
private async executeCallback(
|
||||
handoff: ContextHandoff,
|
||||
result: HandoffResult
|
||||
): Promise<void> {
|
||||
const { endpoint, timeout, retries } = handoff.callback;
|
||||
|
||||
for (let attempt = 0; attempt < retries; attempt++) {
|
||||
try {
|
||||
const response = await fetch(endpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
handoffId: handoff.id,
|
||||
sourceAgent: handoff.sourceAgent,
|
||||
targetAgent: handoff.targetAgent,
|
||||
result
|
||||
}),
|
||||
signal: AbortSignal.timeout(timeout)
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Callback attempt ${attempt + 1} failed:`, error);
|
||||
|
||||
// Wait before retry
|
||||
if (attempt < retries - 1) {
|
||||
await this.sleep(1000 * (attempt + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sleep(ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Context Serialization
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Serialize handoff for transmission
|
||||
*/
|
||||
serialize(handoff: ContextHandoff): string {
|
||||
return JSON.stringify({
|
||||
id: handoff.id,
|
||||
sourceAgent: handoff.sourceAgent,
|
||||
targetAgent: handoff.targetAgent,
|
||||
request: handoff.request,
|
||||
context: handoff.context,
|
||||
constraints: handoff.constraints,
|
||||
callback: handoff.callback,
|
||||
createdAt: handoff.createdAt.toISOString(),
|
||||
expiresAt: handoff.expiresAt.toISOString()
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize handoff from transmission
|
||||
*/
|
||||
deserialize(data: string): ContextHandoff {
|
||||
const parsed = JSON.parse(data);
|
||||
return {
|
||||
...parsed,
|
||||
createdAt: new Date(parsed.createdAt),
|
||||
expiresAt: new Date(parsed.expiresAt)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate handoff integrity
|
||||
*/
|
||||
validate(handoff: ContextHandoff): { valid: boolean; errors: string[] } {
|
||||
const errors: string[] = [];
|
||||
|
||||
if (!handoff.id) errors.push('Missing handoff ID');
|
||||
if (!handoff.sourceAgent) errors.push('Missing source agent');
|
||||
if (!handoff.targetAgent) errors.push('Missing target agent');
|
||||
if (!handoff.request) errors.push('Missing request');
|
||||
|
||||
if (handoff.constraints.timeLimit <= 0) {
|
||||
errors.push('Invalid time limit');
|
||||
}
|
||||
|
||||
if (handoff.expiresAt <= new Date()) {
|
||||
errors.push('Handoff has expired');
|
||||
}
|
||||
|
||||
return {
|
||||
valid: errors.length === 0,
|
||||
errors
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Cleanup
|
||||
// ============================================================================
|
||||
|
||||
private startCleanupTimer(): void {
|
||||
this.cleanupTimer = setInterval(() => {
|
||||
this.cleanup();
|
||||
}, this.config.cleanupInterval);
|
||||
}
|
||||
|
||||
private cleanup(): void {
|
||||
const now = new Date();
|
||||
|
||||
// Remove expired handoffs
|
||||
for (const [id, handoff] of this.activeHandoffs) {
|
||||
if (handoff.expiresAt <= now) {
|
||||
this.cancelHandoff(id, 'Expired');
|
||||
}
|
||||
}
|
||||
|
||||
// Limit completed handoffs
|
||||
if (this.completedHandoffs.size > this.config.maxHandoffs) {
|
||||
const keys = Array.from(this.completedHandoffs.keys());
|
||||
const toRemove = keys.slice(0, this.completedHandoffs.size - this.config.maxHandoffs);
|
||||
toRemove.forEach(key => this.completedHandoffs.delete(key));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop cleanup timer and clear all
|
||||
*/
|
||||
shutdown(): void {
|
||||
if (this.cleanupTimer) {
|
||||
clearInterval(this.cleanupTimer);
|
||||
}
|
||||
this.activeHandoffs.clear();
|
||||
this.completedHandoffs.clear();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Statistics
|
||||
// ============================================================================
|
||||
|
||||
getStats(): {
|
||||
active: number;
|
||||
completed: number;
|
||||
totalCreated: number;
|
||||
successRate: number;
|
||||
averageProcessingTime: number;
|
||||
} {
|
||||
const completed = Array.from(this.completedHandoffs.values());
|
||||
const successful = completed.filter(r => r.success);
|
||||
|
||||
return {
|
||||
active: this.activeHandoffs.size,
|
||||
completed: completed.length,
|
||||
totalCreated: this.handoffCounter,
|
||||
successRate: completed.length > 0 ? successful.length / completed.length : 0,
|
||||
averageProcessingTime: completed.length > 0
|
||||
? completed.reduce((sum, r) => sum + r.processingTime, 0) / completed.length
|
||||
: 0
|
||||
};
|
||||
}
|
||||
|
||||
private generateHandoffId(): string {
|
||||
return `handoff-${Date.now()}-${Math.random().toString(36).substr(2, 6)}`;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Factory Function
|
||||
// ============================================================================
|
||||
|
||||
export function createContextHandoffManager(config?: Partial<HandoffConfig>): ContextHandoffManager {
|
||||
return new ContextHandoffManager(config);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Export
|
||||
// ============================================================================
|
||||
|
||||
export default ContextHandoffManager;
|
||||
Reference in New Issue
Block a user