This commit is contained in:
2025-12-15 15:11:22 +00:00
parent 8662b73adb
commit 19ba58ca40
3 changed files with 231 additions and 25 deletions

View File

@@ -70,6 +70,60 @@ export class DualAgentOrchestrator {
}
}
/**
* Emit a progress event if callback is configured
*/
private emitProgress(event: Omit<interfaces.IProgressEvent, 'timestamp' | 'logLevel' | 'logMessage'>): void {
if (this.options.onProgress) {
const prefix = this.options.logPrefix ? `${this.options.logPrefix} ` : '';
const { logLevel, logMessage } = this.formatProgressEvent(event, prefix);
this.options.onProgress({
...event,
timestamp: new Date(),
logLevel,
logMessage,
});
}
}
/**
* Format a progress event into a log level and message
*/
private formatProgressEvent(
event: Omit<interfaces.IProgressEvent, 'timestamp' | 'logLevel' | 'logMessage'>,
prefix: string
): { logLevel: interfaces.TLogLevel; logMessage: string } {
switch (event.type) {
case 'task_started':
return { logLevel: 'info', logMessage: `${prefix}Task started` };
case 'iteration_started':
return { logLevel: 'info', logMessage: `${prefix}Iteration ${event.iteration}/${event.maxIterations}` };
case 'tool_proposed':
return { logLevel: 'info', logMessage: `${prefix} → Proposing: ${event.toolName}.${event.action}` };
case 'guardian_evaluating':
return { logLevel: 'info', logMessage: `${prefix} ⏳ Guardian evaluating...` };
case 'tool_approved':
return { logLevel: 'info', logMessage: `${prefix} ✓ Approved: ${event.toolName}.${event.action}` };
case 'tool_rejected':
return { logLevel: 'warn', logMessage: `${prefix} ✗ Rejected: ${event.toolName}.${event.action} - ${event.reason}` };
case 'tool_executing':
return { logLevel: 'info', logMessage: `${prefix} ⚡ Executing: ${event.toolName}.${event.action}...` };
case 'tool_completed':
return { logLevel: 'info', logMessage: `${prefix} ✓ Completed: ${event.message}` };
case 'task_completed':
return { logLevel: 'success', logMessage: `${prefix}Task completed in ${event.iteration} iterations` };
case 'clarification_needed':
return { logLevel: 'warn', logMessage: `${prefix}Clarification needed from user` };
case 'max_iterations':
return { logLevel: 'error', logMessage: `${prefix}${event.message}` };
case 'max_rejections':
return { logLevel: 'error', logMessage: `${prefix}${event.message}` };
default:
return { logLevel: 'info', logMessage: `${prefix}${event.type}` };
}
}
/**
* Register a custom tool
*/
@@ -126,7 +180,10 @@ export class DualAgentOrchestrator {
: this.driverProvider;
// NOW create agents with initialized providers
this.driver = new DriverAgent(this.driverProvider, this.options.driverSystemMessage);
this.driver = new DriverAgent(this.driverProvider, {
systemMessage: this.options.driverSystemMessage,
maxHistoryMessages: this.options.maxHistoryMessages,
});
this.guardian = new GuardianAgent(this.guardianProvider, this.options.guardianPolicyPrompt);
// Register any tools that were added before start() with the agents
@@ -192,6 +249,12 @@ export class DualAgentOrchestrator {
let driverResponse = await this.driver.startTask(task);
this.conversationHistory.push(driverResponse);
// Emit task started event
this.emitProgress({
type: 'task_started',
message: task.length > 100 ? task.substring(0, 100) + '...' : task,
});
while (
iterations < this.options.maxIterations! &&
consecutiveRejections < this.options.maxConsecutiveRejections! &&
@@ -199,15 +262,36 @@ export class DualAgentOrchestrator {
) {
iterations++;
// Emit iteration started event
this.emitProgress({
type: 'iteration_started',
iteration: iterations,
maxIterations: this.options.maxIterations,
});
// Check if task is complete
if (this.driver.isTaskComplete(driverResponse.content)) {
completed = true;
finalResult = this.driver.extractTaskResult(driverResponse.content) || driverResponse.content;
// Emit task completed event
this.emitProgress({
type: 'task_completed',
iteration: iterations,
message: 'Task completed successfully',
});
break;
}
// Check if driver needs clarification
if (this.driver.needsClarification(driverResponse.content)) {
// Emit clarification needed event
this.emitProgress({
type: 'clarification_needed',
iteration: iterations,
message: 'Driver needs clarification from user',
});
// Return with clarification needed status
return {
success: false,
@@ -234,6 +318,15 @@ export class DualAgentOrchestrator {
// Process the first proposal (one at a time)
const proposal = proposals[0];
// Emit tool proposed event
this.emitProgress({
type: 'tool_proposed',
iteration: iterations,
toolName: proposal.toolName,
action: proposal.action,
message: `${proposal.toolName}.${proposal.action}`,
});
// Quick validation first
const quickDecision = this.guardian.quickValidate(proposal);
let decision: interfaces.IGuardianDecision;
@@ -241,6 +334,14 @@ export class DualAgentOrchestrator {
if (quickDecision) {
decision = quickDecision;
} else {
// Emit guardian evaluating event
this.emitProgress({
type: 'guardian_evaluating',
iteration: iterations,
toolName: proposal.toolName,
action: proposal.action,
});
// Full AI evaluation
decision = await this.guardian.evaluate(proposal, task);
}
@@ -248,6 +349,14 @@ export class DualAgentOrchestrator {
if (decision.decision === 'approve') {
consecutiveRejections = 0;
// Emit tool approved event
this.emitProgress({
type: 'tool_approved',
iteration: iterations,
toolName: proposal.toolName,
action: proposal.action,
});
// Execute the tool
const tool = this.tools.get(proposal.toolName);
if (!tool) {
@@ -260,8 +369,25 @@ export class DualAgentOrchestrator {
}
try {
// Emit tool executing event
this.emitProgress({
type: 'tool_executing',
iteration: iterations,
toolName: proposal.toolName,
action: proposal.action,
});
const result = await tool.execute(proposal.action, proposal.params);
// Emit tool completed event
this.emitProgress({
type: 'tool_completed',
iteration: iterations,
toolName: proposal.toolName,
action: proposal.action,
message: result.success ? 'success' : result.error,
});
// Build result message (prefer summary if provided, otherwise stringify result)
let resultMessage: string;
if (result.success) {
@@ -306,6 +432,15 @@ export class DualAgentOrchestrator {
// Rejected
consecutiveRejections++;
// Emit tool rejected event
this.emitProgress({
type: 'tool_rejected',
iteration: iterations,
toolName: proposal.toolName,
action: proposal.action,
reason: decision.reason,
});
// Build rejection feedback
let feedback = `TOOL CALL REJECTED by Guardian:\n`;
feedback += `- Reason: ${decision.reason}\n`;
@@ -337,8 +472,21 @@ export class DualAgentOrchestrator {
if (!completed) {
if (iterations >= this.options.maxIterations!) {
status = 'max_iterations_reached';
// Emit max iterations event
this.emitProgress({
type: 'max_iterations',
iteration: iterations,
maxIterations: this.options.maxIterations,
message: `Maximum iterations (${this.options.maxIterations}) reached`,
});
} else if (consecutiveRejections >= this.options.maxConsecutiveRejections!) {
status = 'max_rejections_reached';
// Emit max rejections event
this.emitProgress({
type: 'max_rejections',
iteration: iterations,
message: `Maximum consecutive rejections (${this.options.maxConsecutiveRejections}) reached`,
});
}
}