$step_class, 'metadata' => $metadata ); return true; } /** * Unregister a step * * @param string $step_type * @return bool */ public static function unregister($step_type) { if (isset(self::$steps[$step_type])) { unset(self::$steps[$step_type]); return true; } return false; } /** * Check if a step type is registered * * @param string $step_type * @return bool */ public static function is_registered($step_type) { return isset(self::$steps[$step_type]); } /** * Create a step instance * * @param string $step_type * @param array $config Step configuration * @return AIGH_Pipeline_Step|WP_Error */ public static function create_step($step_type, $config = array()) { if (!isset(self::$steps[$step_type])) { return new WP_Error( 'unknown_step', sprintf('Step type "%s" is not registered', $step_type) ); } $step_class = self::$steps[$step_type]['class']; try { $step = new $step_class($config); return $step; } catch (Exception $e) { return new WP_Error( 'step_creation_failed', sprintf('Failed to create step "%s": %s', $step_type, $e->getMessage()) ); } } /** * Create step from array representation * * @param array $data Must contain 'step_type' and optionally 'config' * @return AIGH_Pipeline_Step|WP_Error */ public static function create_from_array($data) { if (!isset($data['step_type'])) { return new WP_Error('missing_step_type', 'Step data must include step_type'); } $step_type = $data['step_type']; $config = isset($data['config']) ? $data['config'] : array(); return self::create_step($step_type, $config); } /** * Get all registered steps * * @param string|null $category Filter by category (input, processing, refinement, output, control) * @return array */ public static function get_all_steps($category = null) { if (!$category) { return self::$steps; } // Filter by category $filtered = array(); foreach (self::$steps as $step_type => $data) { // Create temp instance to get category $step = self::create_step($step_type); if (!is_wp_error($step) && $step->get_category() === $category) { $filtered[$step_type] = $data; } } return $filtered; } /** * Get metadata for a registered step * * @param string $step_type * @return array|null */ public static function get_step_metadata($step_type) { if (!isset(self::$steps[$step_type])) { return null; } // Create temp instance to get metadata $step = self::create_step($step_type); if (is_wp_error($step)) { return null; } return $step->get_metadata(); } /** * Get list of step types by category * * @return array Associative array with categories as keys */ public static function get_steps_by_category() { $categorized = array( 'input' => array(), 'processing' => array(), 'refinement' => array(), 'output' => array(), 'control' => array() ); foreach (self::$steps as $step_type => $data) { $step = self::create_step($step_type); if (!is_wp_error($step)) { $category = $step->get_category(); if (!isset($categorized[$category])) { $categorized[$category] = array(); } $categorized[$category][$step_type] = $step->get_metadata(); } } return $categorized; } /** * Search for steps matching criteria * * @param array $criteria Search criteria (name, description, category, etc.) * @return array Matching step types */ public static function search($criteria) { $matches = array(); foreach (self::$steps as $step_type => $data) { $step = self::create_step($step_type); if (is_wp_error($step)) { continue; } $metadata = $step->get_metadata(); $match = true; foreach ($criteria as $key => $value) { if ($key === 'name' && stripos($metadata['step_name'], $value) === false) { $match = false; break; } if ($key === 'description' && stripos($metadata['description'], $value) === false) { $match = false; break; } if ($key === 'category' && $metadata['category'] !== $value) { $match = false; break; } } if ($match) { $matches[$step_type] = $metadata; } } return $matches; } /** * Register all default steps (existing functionality converted to steps) */ public static function register_defaults() { if (self::$defaults_registered) { return; } // Input steps self::register('input_topic', 'AIGH_Step_Input_Topic', array( 'label' => 'Topic Input', 'icon' => 'dashicons-edit' )); // Processing steps self::register('research_urls', 'AIGH_Step_Research_Urls', array( 'label' => 'Research URLs', 'icon' => 'dashicons-admin-links' )); self::register('generate_draft', 'AIGH_Step_Generate_Draft', array( 'label' => 'Generate Draft', 'icon' => 'dashicons-media-document' )); // Research steps self::register('web_search', 'AIGH_Step_Web_Search', array( 'label' => 'Web Search', 'icon' => 'dashicons-search' )); self::register('find_statistics', 'AIGH_Step_Find_Statistics', array( 'label' => 'Find Statistics', 'icon' => 'dashicons-chart-bar' )); self::register('find_examples', 'AIGH_Step_Find_Examples', array( 'label' => 'Find Examples', 'icon' => 'dashicons-lightbulb' )); self::register('find_expert_quotes', 'AIGH_Step_Find_Expert_Quotes', array( 'label' => 'Find Expert Quotes', 'icon' => 'dashicons-format-quote' )); // Output steps self::register('save_draft', 'AIGH_Step_Save_Draft', array( 'label' => 'Save as Draft', 'icon' => 'dashicons-saved' )); // Refinement steps self::register('refine_add_detail', 'AIGH_Step_Refine_Add_Detail', array( 'label' => 'Add More Detail', 'icon' => 'dashicons-plus-alt' )); self::register('refine_add_examples', 'AIGH_Step_Refine_Add_Examples', array( 'label' => 'Add Examples', 'icon' => 'dashicons-lightbulb' )); self::register('refine_add_statistics', 'AIGH_Step_Refine_Add_Statistics', array( 'label' => 'Add Statistics', 'icon' => 'dashicons-chart-bar' )); self::register('refine_improve_intro', 'AIGH_Step_Refine_Improve_Intro', array( 'label' => 'Improve Introduction', 'icon' => 'dashicons-welcome-write-blog' )); self::register('refine_improve_conclusion', 'AIGH_Step_Refine_Improve_Conclusion', array( 'label' => 'Improve Conclusion', 'icon' => 'dashicons-flag' )); self::register('refine_improve_seo', 'AIGH_Step_Refine_Improve_SEO', array( 'label' => 'Improve SEO', 'icon' => 'dashicons-search' )); self::register('refine_make_longer', 'AIGH_Step_Refine_Make_Longer', array( 'label' => 'Make Longer', 'icon' => 'dashicons-arrow-up-alt' )); self::register('refine_make_shorter', 'AIGH_Step_Refine_Make_Shorter', array( 'label' => 'Make Shorter', 'icon' => 'dashicons-arrow-down-alt' )); self::register('refine_custom', 'AIGH_Step_Refine_Custom', array( 'label' => 'Custom Refinement', 'icon' => 'dashicons-edit' )); self::$defaults_registered = true; } /** * Get count of registered steps * * @return int */ public static function count() { return count(self::$steps); } /** * Clear all registrations (mainly for testing) */ public static function clear() { self::$steps = array(); self::$defaults_registered = false; } /** * Validate a pipeline configuration * * @param array $pipeline_config Array of step configurations * @return bool|WP_Error */ public static function validate_pipeline_config($pipeline_config) { if (empty($pipeline_config)) { return new WP_Error('empty_pipeline', 'Pipeline configuration is empty'); } foreach ($pipeline_config as $index => $step_config) { if (!isset($step_config['step_type'])) { return new WP_Error( 'missing_step_type', sprintf('Step at index %d is missing step_type', $index) ); } if (!self::is_registered($step_config['step_type'])) { return new WP_Error( 'unknown_step', sprintf('Step type "%s" at index %d is not registered', $step_config['step_type'], $index) ); } } return true; } /** * Create a pipeline from configuration array * * @param array $pipeline_config Array of step configurations * @return array|WP_Error Array of step instances or error */ public static function create_pipeline($pipeline_config) { $validation = self::validate_pipeline_config($pipeline_config); if (is_wp_error($validation)) { return $validation; } $steps = array(); foreach ($pipeline_config as $step_config) { $step = self::create_from_array($step_config); if (is_wp_error($step)) { return $step; } $steps[] = $step; } return $steps; } }