* @author Maximum Software Inc * @license GPL-3.0-only * @link https://agenistrator.com/ * * SPDX-FileCopyrightText: 2025-2026 Alex Ruban * SPDX-FileCopyrightText: 2025-2026 Maximum Software Inc * SPDX-License-Identifier: GPL-3.0-only */ namespace Agenistrator; // Direct access prevention if ( ! defined( 'ABSPATH' ) ) { exit; } /** * Tool class. */ abstract class Tool { /** * Constructor * @since 1.0.0 */ public function __construct() { // Initialize the tool } /** * Get the tool ID (machine-readable identifier) * * This is used for API calls, configuration keys, and internal lookups. * Should be a snake_case string like 'create_post' or 'search_content'. * * @return string Tool ID * @since 1.0.0 */ abstract public function get_id(); /** * Get the tool name (human-readable display name) * * This is used for UI display purposes. * Should be a properly formatted name like 'Create Post' or 'Search Content'. * * @return string Tool name * @since 1.0.0 */ abstract public function get_name(); /** * Get the tool description * * A brief description of what the tool does, suitable for display in the * admin UI and the list_all_tools output. * * @return string Tool description * @since 1.0.0 */ abstract public function get_description(); /** * Get brief usage hints for the LLM * * Description instructions provide hints about when to use this tool and * how it relates to other tools (e.g., "Use list_post_types to see available types"). * These are appended to the tool description in list_all_tools output and tool * definitions sent to the LLM, but NOT shown in the admin UI. * * @return string Brief usage hints (empty by default) * @since 1.0.0 */ public function get_description_instructions() { return ''; } /** * Get usage instructions for the LLM * * Instructions provide detailed guidance on how to use the tool effectively. * Unlike descriptions, instructions are only sent to the LLM after the tool * is imported and are not shown in the admin UI or list_all_tools output. * * @return string Tool usage instructions (empty by default) * @since 1.0.0 */ public function get_instructions() { return ''; } /** * Get the parameters for this tool * * MUST return a complete JSON Schema object with the following structure: * [ * 'type' => 'object', * 'properties' => [ * 'param1' => ['type' => 'string', 'description' => 'Description of param1'], * 'param2' => ['type' => 'integer', 'description' => 'Description of param2'], * ... * ], * 'required' => ['param1', 'param2', ...] // Always include this, even if empty array * ] * * @return array Complete parameters schema in JSON Schema format * @since 1.0.0 */ abstract public function get_parameters(); /** * Check if this tool is read-only (has no side effects) * * Read-only tools only retrieve data without modifying state. * Read-write tools create, update, or delete content. * * @return bool True if read-only, false if read-write * @since 1.0.0 */ abstract public function is_read_only(); /** * Check if this tool is enabled * * @return bool True if enabled, false otherwise * @since 1.0.0 */ public function is_enabled() { // Delegate to Tool_Manager return Tool_Manager::get_instance()->is_tool_enabled( $this->get_id() ); } /** * Get the default enabled status for this tool * * By default, read-only tools are enabled and read-write tools are disabled. * Individual tools can override this method to change the default behavior. * * @return bool True if enabled by default, false otherwise * @since 1.0.0 */ public function get_default_enabled_status() { return $this->is_read_only(); } /** * Check if this tool is always enabled (cannot be disabled by user) * * Core tools like list_all_tools, import_tools, unimport_tools return true. * Regular tools return false and can be enabled/disabled via settings. * * @return bool True if always enabled, false otherwise * @since 1.0.0 */ public function is_always_enabled() { return false; } /** * Check if this tool is always imported (always in context) * * Core tools like list_all_tools, import_tools, unimport_tools return true. * Regular tools return false and must be imported to appear in context. * * @return bool True if always imported, false otherwise * @since 1.0.0 */ public function is_always_imported() { return false; } /** * Check if the current user has permission to execute this tool * * @return bool Whether the user has permission * @since 1.0.0 */ abstract public function current_user_can_execute(); /** * Run the tool with the given arguments * * @param array $args Arguments for the tool as an associative array * @return mixed Result of running the tool * @since 1.0.0 */ public function run( $args ) { // Validate arguments against schema (basic validation) $this->validate_arguments( $args ); // Call the abstract execute method to run the tool return $this->execute( $args ); } /** * Validate arguments against the schema * * @param array $args Arguments to validate * @throws \Exception If validation fails * @since 1.0.0 */ protected function validate_arguments( $args ) { // Get parameters schema $schema = $this->get_parameters(); // Check required parameters if ( isset( $schema['required'] ) && is_array( $schema['required'] ) ) { foreach ( $schema['required'] as $required_param ) { if ( ! isset( $args[ $required_param ] ) ) { // phpcs:disable WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception messages are not HTML output throw new \Exception( String_Utils::replace_tags( \__( 'Missing required argument: {required_param}', 'agenistrator' ), array( 'required_param' => $required_param ) ) ); // phpcs:enable WordPress.Security.EscapeOutput.ExceptionNotEscaped } } } // Basic type checking could be added here // For more complex validation, a full JSON Schema validator would be needed } /** * Execute the tool with the given arguments * This is the main method that should be implemented by each tool * * @param array $args Validated arguments for the tool * @return mixed Result of executing the tool * @since 1.0.0 */ abstract protected function execute( $args ); /** * Create a success response * * @param string $message Success message * @param array $data Optional data to include in response * @return array Formatted success response * @since 1.0.0 */ protected function success_response( $message, $data = array() ) { return array( 'success' => true, 'message' => $message, 'data' => $data, ); } /** * Create an error response * * @param string $message Error message * @param array $data Optional data to include in response * @return array Formatted error response * @since 1.0.0 */ protected function error_response( $message, $data = array() ) { return array( 'success' => false, 'message' => $message, 'data' => $data, ); } }