/ src / agents / workflows / bug-fix.js
bug-fix.js
  1  /**
  2   * Bug Fix Workflow
  3   *
  4   * Automated workflow: Triage → Developer → QA → Security
  5   *
  6   * Usage:
  7   *   import { createBugFixWorkflow } from './workflows/bug-fix.js';
  8   *   const workflowId = await createBugFixWorkflow(errorMessage, stackTrace);
  9   */
 10  
 11  import { createAgentTask } from '../utils/task-manager.js';
 12  import Logger from '../../utils/logger.js';
 13  import { getAll } from '../../utils/db.js';
 14  
 15  const logger = new Logger('BugFixWorkflow');
 16  
 17  /**
 18   * Create a bug fix workflow
 19   *
 20   * @param {string} errorMessage - Error message
 21   * @param {string} [stackTrace=''] - Stack trace
 22   * @param {string} [stage='unknown'] - Pipeline stage where error occurred
 23   * @param {number} [frequency=1] - How many times the error has occurred
 24   * @param {Object} [options] - Additional options
 25   * @param {number} [options.priority] - Override calculated priority
 26   * @param {string} [options.created_by='system'] - Who created the workflow
 27   * @returns {Promise<number>} - Triage task ID (parent of the workflow)
 28   */
 29  export async function createBugFixWorkflow(
 30    errorMessage,
 31    stackTrace = '',
 32    stage = 'unknown',
 33    frequency = 1,
 34    options = {}
 35  ) {
 36    const { priority, created_by = 'system' } = options;
 37  
 38    logger.info('Creating bug fix workflow', {
 39      error: errorMessage.substring(0, 100),
 40      stage,
 41      frequency,
 42    });
 43  
 44    // Step 1: Create Triage task (will route to Developer)
 45    const triageTaskId = await createAgentTask({
 46      task_type: 'classify_error',
 47      assigned_to: 'triage',
 48      created_by,
 49      priority: priority || 5,
 50      context: {
 51        error_message: errorMessage,
 52        stack_trace: stackTrace,
 53        stage,
 54        frequency,
 55      },
 56    });
 57  
 58    logger.info('Bug fix workflow created', {
 59      workflow_id: triageTaskId,
 60      stage,
 61    });
 62  
 63    return triageTaskId;
 64  }
 65  
 66  /**
 67   * Create multiple bug fix workflows from a list of errors
 68   *
 69   * @param {Array<Object>} errors - Array of error objects
 70   * @param {string} errors[].message - Error message
 71   * @param {string} [errors[].stack] - Stack trace
 72   * @param {string} [errors[].stage] - Pipeline stage
 73   * @param {number} [errors[].frequency] - Occurrence count
 74   * @returns {Promise<Array<number>>} - Array of workflow IDs
 75   */
 76  export async function createBulkBugFixWorkflows(errors) {
 77    const workflowIds = [];
 78  
 79    for (const error of errors) {
 80      try {
 81        const workflowId = await createBugFixWorkflow(
 82          error.message,
 83          error.stack || '',
 84          error.stage || 'unknown',
 85          error.frequency || 1,
 86          { created_by: error.created_by || 'system' }
 87        );
 88        workflowIds.push(workflowId);
 89      } catch (err) {
 90        logger.error('Failed to create bug fix workflow', {
 91          error: error.message,
 92          err: err.message,
 93        });
 94      }
 95    }
 96  
 97    return workflowIds;
 98  }
 99  
100  /**
101   * Get workflow status
102   *
103   * @param {number} workflowId - Triage task ID (parent)
104   * @returns {Promise<Object>} - Workflow status
105   */
106  export async function getBugFixWorkflowStatus(workflowId) {
107    // Get all tasks in the workflow chain
108    const tasks = await getAll(
109      `WITH RECURSIVE workflow_chain AS (
110         SELECT * FROM tel.agent_tasks WHERE id = $1
111         UNION ALL
112         SELECT t.* FROM tel.agent_tasks t
113         INNER JOIN workflow_chain wc ON t.parent_task_id = wc.id
114       )
115       SELECT * FROM workflow_chain
116       ORDER BY id ASC`,
117      [workflowId]
118    );
119  
120    const status = {
121      workflow_id: workflowId,
122      created_at: tasks[0]?.created_at,
123      stages: tasks.map(t => ({
124        agent: t.assigned_to,
125        task_type: t.task_type,
126        status: t.status,
127        started_at: t.started_at,
128        completed_at: t.completed_at,
129        error_message: t.error_message,
130      })),
131      current_stage: tasks.find(t => t.status === 'running' || t.status === 'pending'),
132      is_complete: tasks.every(t => t.status === 'completed'),
133      has_failures: tasks.some(t => t.status === 'failed'),
134      is_blocked: tasks.some(t => t.status === 'blocked'),
135    };
136  
137    return status;
138  }