get_articles(); $aizl_functions = $aizl_db_handler->get_functions(); class Create { private $table_agent; private $table_conversation; public function __construct() { $this->table_agent = Config::get_table_name('agent'); $this->table_conversation = Config::get_table_name('conversation'); add_action('wp_ajax_aizl_create_agent', array($this, 'aizl_create_agent')); add_action('wp_ajax_aizl_get_agent', array($this, 'aizl_get_agent')); add_action('wp_ajax_nopriv_aizl_get_agent', array($this, 'aizl_get_agent')); add_action('wp_ajax_aizl_delete_agent', array($this, 'aizl_delete_agent')); add_action('wp_ajax_aizl_check_function_availability', array($this, 'aizl_check_function_availability')); } public function aizl_create_agent() { if (!check_ajax_referer('aizl_setting', 'nonce', false)) { wp_send_json_error('Invalid nonce.'); return; } if (!isset($_POST['name'])) { wp_send_json_error('No agent name provided.'); return; } $agent_id = isset($_POST['agent_id']) ? sanitize_text_field(wp_unslash($_POST['agent_id'])) : null; $name = sanitize_text_field(wp_unslash($_POST['name'])); $instructions = isset($_POST['instructions']) ? wp_kses_post(wp_unslash($_POST['instructions'])) : ''; $greeting_message = isset($_POST['greeting_message']) ? wp_kses_post(wp_unslash($_POST['greeting_message'])) : ''; $model = isset($_POST['model']) ? sanitize_text_field(wp_unslash($_POST['model'])) : ''; $selected_articles = isset($_POST['articles']) ? array_map('intval', $_POST['articles']) : []; $selected_functions = isset($_POST['functions']) ? array_map('intval', $_POST['functions']) : []; // Create or update vector store with selected articles $vector_store_id = null; if (!empty($selected_articles)) { // Get file_ids from selected article_ids $file_ids = $this->get_file_ids_from_articles($selected_articles); if ($agent_id) { // UPDATE case: Get existing vector_store_id $db_handler = new DBHandler(); $existing_agent = $db_handler->get_agent_by_id($agent_id); $existing_vector_store_id = $existing_agent->vector_store_id ?? null; // Get previously selected article_ids $old_article_ids = json_decode($existing_agent->article_ids, true) ?: []; $old_file_ids = $this->get_file_ids_from_articles($old_article_ids); // Calculate diff $files_to_add = array_diff($file_ids, $old_file_ids); $files_to_remove = array_diff($old_file_ids, $file_ids); // Update vector store $vector_store_id = $this->update_vector_store( $existing_vector_store_id, $files_to_add, $files_to_remove ); } else { // CREATE case: Create new vector store $vector_store_id = $this->create_vector_store($file_ids); } } $tools_object = $this->get_tools_object($vector_store_id, $selected_functions); $tools = $tools_object['tools']; if ($agent_id) { $this->update_agent($name, $instructions, $greeting_message, $model, $selected_articles, $selected_functions, $tools, $vector_store_id, $agent_id); wp_send_json_success('The agent has been updated.'); } else { $agent_id = $this->save_agent($name, $instructions, $greeting_message, $model, $selected_articles, $selected_functions, $tools, $vector_store_id); wp_send_json_success('The agent has been created.'); } } private function save_agent($name, $instructions, $greeting_message, $model, $article_ids, $function_ids, $tools, $vector_store_id) { global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery $result = $wpdb->insert($this->table_agent, array( 'name' => $name, 'instructions' => $instructions, 'greeting_message' => $greeting_message, 'model' => $model, 'article_ids' => json_encode($article_ids), 'function_ids' => json_encode($function_ids), 'tools' => json_encode($tools), 'vector_store_id' => $vector_store_id, 'created_time' => gmdate('Y-m-d H:i:s'), 'updated_time' => gmdate('Y-m-d H:i:s'), )); if ($result === false) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log error_log('Database insert error: ' . $wpdb->last_error); return false; } return $wpdb->insert_id; } private function update_agent($name, $instructions, $greeting_message, $model, $article_ids, $function_ids, $tools, $vector_store_id, $agent_id) { global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $result = $wpdb->update($this->table_agent, array( 'name' => $name, 'instructions' => $instructions, 'greeting_message' => $greeting_message, 'model' => $model, 'article_ids' => json_encode($article_ids), 'function_ids' => json_encode($function_ids), 'tools' => json_encode($tools), 'vector_store_id' => $vector_store_id, 'updated_time' => gmdate('Y-m-d H:i:s'), ), array('id' => $agent_id)); if ($result === false) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log error_log('Database update error: ' . $wpdb->last_error); return false; } return true; } private function get_tools_object($vector_store_id, $function_ids) { global $wpdb; $tools = []; $db_handler = new DBHandler(); // Add file search tool with single vector store if (!empty($vector_store_id)) { $tools[] = array( 'type' => 'file_search', 'vector_store_ids' => [$vector_store_id], "max_num_results" => 3 ); } // Add function tools foreach ($function_ids as $function_id) { $function_data = $db_handler->get_function_by_id($function_id); if ($function_data) { $tools[] = json_decode($function_data->definition, true); } } return [ 'tools' => $tools ]; } private function get_file_ids_from_articles($article_ids) { if (empty($article_ids)) { return []; } $db_handler = new DBHandler(); $file_ids = []; foreach ($article_ids as $article_id) { $file_id = $db_handler->get_file_id_by_article_id($article_id); if ($file_id) { $file_ids[] = $file_id; } } return $file_ids; } private function create_vector_store($file_ids) { $api_url = Config::get_api_endpoint('vector'); $db_handler = new DBHandler(); $access_key = $db_handler->get_access_key(); if (!$access_key) { wp_send_json_error('Invalid Access Key'); return null; } $api_response = wp_remote_post($api_url, array( 'body' => json_encode(array( 'file_ids' => $file_ids, 'action' => 'create' )), 'headers' => array( 'Content-Type' => 'application/json', 'x-access-key' => $access_key, 'x-plugin-source' => 'aizlabs_chat_agent' ), 'timeout' => 60, )); if (is_wp_error($api_response)) { wp_send_json_error('Failed to create vector store.'); return null; } if (wp_remote_retrieve_response_code($api_response) != 200) { wp_send_json_error('Failed to create vector store.'); return null; } $response_body = json_decode(wp_remote_retrieve_body($api_response), true); return $response_body['vector_store_id'] ?? null; } private function update_vector_store($vector_store_id, $files_to_add, $files_to_remove) { // If no vector store exists yet, create one with the new files if (empty($vector_store_id) && !empty($files_to_add)) { return $this->create_vector_store($files_to_add); } // If there are no changes, return the existing vector store ID if (empty($files_to_add) && empty($files_to_remove)) { return $vector_store_id; } $api_url = Config::get_api_endpoint('vector'); $db_handler = new DBHandler(); $access_key = $db_handler->get_access_key(); if (!$access_key) { wp_send_json_error('Invalid Access Key'); return $vector_store_id; } $api_response = wp_remote_post($api_url, array( 'body' => json_encode(array( 'vector_store_id' => $vector_store_id, 'action' => 'update', 'files_to_add' => array_values($files_to_add), 'files_to_remove' => array_values($files_to_remove) )), 'headers' => array( 'Content-Type' => 'application/json', 'x-access-key' => $access_key, 'x-plugin-source' => 'aizlabs_chat_agent' ), 'timeout' => 60, )); if (is_wp_error($api_response)) { // Return existing vector_store_id if update fails return $vector_store_id; } if (wp_remote_retrieve_response_code($api_response) != 200) { // Return existing vector_store_id if update fails return $vector_store_id; } $response_body = json_decode(wp_remote_retrieve_body($api_response), true); return $response_body['vector_store_id'] ?? $vector_store_id; } public function aizl_get_agent() { if (!check_ajax_referer('aizl_setting', 'nonce', false)) { wp_send_json_error('Invalid nonce.'); return; } if (!isset($_POST['agent_id'])) { wp_send_json_error('No agent ID provided.'); return; } global $wpdb; $db_handler = new DBHandler(); $agent_id = intval($_POST['agent_id']); $agent = $db_handler->get_agent_by_id($agent_id); if (!$agent) { wp_send_json_error('Agent not found.'); return; } $agent->instructions = wp_kses_post(stripslashes($agent->instructions)); $agent->greeting_message = wp_kses_post(stripslashes($agent->greeting_message)); wp_send_json_success($agent); } public function aizl_delete_agent() { if (!check_ajax_referer('aizl_setting', 'nonce', false)) { wp_send_json_error('Invalid nonce.'); return; } if (!current_user_can('manage_options')) { wp_send_json_error('Unauthorized access.'); return; } if (!isset($_POST['agent_id'])) { wp_send_json_error('No agent ID provided.'); return; } global $wpdb; $agent_id = intval($_POST['agent_id']); // Get agent's vector_store_id before deletion // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $agent = $wpdb->get_row($wpdb->prepare( "SELECT vector_store_id FROM `{$this->table_agent}` WHERE id = %d", $agent_id )); // Delete OpenAI resources if vector_store_id exists if ($agent && !empty($agent->vector_store_id)) { $this->delete_agent_resources($agent->vector_store_id); } // Delete database records // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->delete($this->table_agent, array('id' => $agent_id), array('%d')); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->delete($this->table_conversation, array('agent_id' => $agent_id), array('%d')); wp_send_json_success('The agent has been deleted.'); } /** * Delete agent resources from OpenAI (vector store and file associations) */ private function delete_agent_resources($vector_store_id) { $api_url = Config::get_api_endpoint('delete'); $db_handler = new DBHandler(); $access_key = $db_handler->get_access_key(); if (!$access_key) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log error_log('Delete agent resources: Invalid access key'); return false; } $api_response = wp_remote_post($api_url, array( 'body' => wp_json_encode(array( 'action' => 'delete_agent', 'vector_store_id' => $vector_store_id )), 'headers' => array( 'Content-Type' => 'application/json', 'x-access-key' => $access_key, 'x-plugin-source' => 'aizlabs_chat_agent' ), 'timeout' => 60, )); if (is_wp_error($api_response)) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log error_log('Delete agent resources error: ' . $api_response->get_error_message()); return false; } $response_code = wp_remote_retrieve_response_code($api_response); if ($response_code !== 200) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log error_log('Delete agent resources failed with code: ' . $response_code); return false; } return true; } public function aizl_check_function_availability() { if (!check_ajax_referer('aizl_setting', 'nonce', false)) { wp_send_json_error('Invalid nonce.'); return; } $db_handler = new DBHandler(); $functions = $db_handler->get_functions(); $availability = array(); foreach ($functions as $function) { $is_available = $db_handler->is_function_available($function); $availability[$function->id] = $is_available; } wp_send_json_success($availability); } }