← back to Designer Wallcoverings

DW-Agents/dw-agents/agent-parallel-processes/shared-task-reporter.ts

230 lines

/**
 * Shared Task Orchestrator Reporter
 *
 * This module provides a simple interface for all agents to report their
 * tasks to the central task orchestrator (port 9900).
 *
 * Usage:
 *   import { reportTaskStart, reportTaskComplete, reportTaskFailed } from './shared-task-reporter';
 *
 *   // When starting work
 *   const taskId = await reportTaskStart('Process York Products', 'Processing 500 York products', 'high', 'york');
 *
 *   // When work completes
 *   await reportTaskComplete(taskId, 'Processed 500 products successfully');
 *
 *   // If work fails
 *   await reportTaskFailed(taskId, 'Failed due to API error');
 */

const TASK_ORCHESTRATOR_URL = 'http://localhost:9900';

interface TaskMetadata {
  agentPort?: number;
  url?: string;
  workProgress?: {
    current: number;
    total: number;
  };
  [key: string]: any;
}

/**
 * Report that a task has started
 */
export async function reportTaskStart(
  title: string,
  description: string,
  priority: 'low' | 'medium' | 'high' | 'critical' = 'medium',
  agentName: string,
  metadata: TaskMetadata = {}
): Promise<string | null> {
  try {
    const response = await fetch(`${TASK_ORCHESTRATOR_URL}/api/webhook/task`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        title,
        description,
        priority,
        source: agentName,
        metadata: {
          ...metadata,
          autoStarted: true,
          startedAt: new Date().toISOString()
        }
      })
    });

    if (response.ok) {
      const result = await response.json();
      console.log(`✅ Task reported to orchestrator: ${result.taskId}`);

      // Immediately update to in_progress
      if (result.taskId) {
        await updateTaskStatus(result.taskId, 'in_progress');
      }

      return result.taskId;
    } else {
      console.error('❌ Failed to report task to orchestrator:', response.statusText);
      return null;
    }
  } catch (error) {
    console.error('❌ Error reporting task to orchestrator:', error);
    return null;
  }
}

/**
 * Update task status
 */
export async function updateTaskStatus(
  taskId: string,
  status: 'pending' | 'assigned' | 'in_progress' | 'blocked' | 'completed' | 'failed',
  details?: string
): Promise<boolean> {
  try {
    const response = await fetch(`${TASK_ORCHESTRATOR_URL}/api/tasks/${taskId}/status`, {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ status, details })
    });

    if (response.ok) {
      console.log(`✅ Task ${taskId} updated to ${status}`);
      return true;
    } else {
      console.error(`❌ Failed to update task ${taskId}:`, response.statusText);
      return false;
    }
  } catch (error) {
    console.error(`❌ Error updating task ${taskId}:`, error);
    return false;
  }
}

/**
 * Update work progress (e.g., 44/2000 products processed)
 */
export async function updateTaskProgress(
  taskId: string,
  current: number,
  total: number,
  details?: string
): Promise<boolean> {
  try {
    const response = await fetch(`${TASK_ORCHESTRATOR_URL}/api/tasks/${taskId}`, {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        metadata: {
          workProgress: { current, total }
        },
        ...(details && { details })
      })
    });

    if (response.ok) {
      return true;
    }
    return false;
  } catch (error) {
    console.error(`❌ Error updating task progress ${taskId}:`, error);
    return false;
  }
}

/**
 * Report that a task has completed successfully
 */
export async function reportTaskComplete(
  taskId: string | null,
  details: string = 'Task completed successfully'
): Promise<boolean> {
  if (!taskId) {
    console.warn('⚠️ No taskId provided, skipping completion report');
    return false;
  }

  return await updateTaskStatus(taskId, 'completed', details);
}

/**
 * Report that a task has failed
 */
export async function reportTaskFailed(
  taskId: string | null,
  details: string = 'Task failed'
): Promise<boolean> {
  if (!taskId) {
    console.warn('⚠️ No taskId provided, skipping failure report');
    return false;
  }

  return await updateTaskStatus(taskId, 'failed', details);
}

/**
 * Report that a task is blocked
 */
export async function reportTaskBlocked(
  taskId: string | null,
  reason: string
): Promise<boolean> {
  if (!taskId) {
    console.warn('⚠️ No taskId provided, skipping blocked report');
    return false;
  }

  return await updateTaskStatus(taskId, 'blocked', reason);
}

/**
 * Convenience function for long-running operations
 * Automatically reports start, progress, and completion
 */
export class TaskReporter {
  private taskId: string | null = null;
  private title: string;
  private agentName: string;

  constructor(title: string, description: string, agentName: string, priority: 'low' | 'medium' | 'high' | 'critical' = 'medium', metadata: TaskMetadata = {}) {
    this.title = title;
    this.agentName = agentName;

    // Start the task immediately
    reportTaskStart(title, description, priority, agentName, metadata).then(taskId => {
      this.taskId = taskId;
    });
  }

  async updateProgress(current: number, total: number, details?: string): Promise<void> {
    if (this.taskId) {
      await updateTaskProgress(this.taskId, current, total, details);
    }
  }

  async complete(details?: string): Promise<void> {
    if (this.taskId) {
      await reportTaskComplete(this.taskId, details || `${this.title} completed successfully`);
    }
  }

  async fail(details?: string): Promise<void> {
    if (this.taskId) {
      await reportTaskFailed(this.taskId, details || `${this.title} failed`);
    }
  }

  async block(reason: string): Promise<void> {
    if (this.taskId) {
      await reportTaskBlocked(this.taskId, reason);
    }
  }

  getTaskId(): string | null {
    return this.taskId;
  }
}