providerInfo = $providerInfo; $this->settingsService = $settingsService; add_action('admin_bar_menu', [$this, 'addToolbarNode'], 100); add_action('admin_enqueue_scripts', [$this, 'enqueueAssets']); add_action('admin_footer', [$this, 'renderRoot']); } /** * Adds the chat icon to the admin bar. * * @param WP_Admin_Bar $wp_admin_bar The admin bar instance. * * @return void * @since 1.0.0 */ public function addToolbarNode(WP_Admin_Bar $wp_admin_bar): void { if (! is_admin() || ! current_user_can('manage_options')) { return; } // Hide the icon on the AgentMod admin page itself. // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only URL parameter check to determine current admin page; no form data is processed. $current_page = isset($_GET['page']) ? sanitize_key(wp_unslash($_GET['page'])) : ''; if ('agent-mod' === $current_page) { return; } $iconUrl = esc_url(AGENT_MOD_URL . 'includes/Presentation/Admin/Assets/img/agent_mod_icon.png'); $title = '' . '' . esc_html__('Assistant', 'agent-mod') . ''; $wp_admin_bar->add_node( [ 'id' => self::NODE_ID, 'title' => $title, 'href' => '#', 'meta' => [ 'title' => esc_attr__('Open AgentMod Assistant', 'agent-mod'), ], ] ); } /** * Enqueues the widget script and styles, plus localized config. * * @return void * @since 1.0.0 */ public function enqueueAssets(): void { if (! current_user_can('manage_options')) { return; } $asset_path = AGENT_MOD_PATH . 'build/admin-chat/index.asset.php'; // Silently bail if the widget has not been built yet. if (! is_readable($asset_path)) { return; } $asset = require $asset_path; wp_enqueue_script( self::HANDLE, AGENT_MOD_URL . 'build/admin-chat/index.js', $asset['dependencies'], $asset['version'], true ); wp_enqueue_style('wp-components'); wp_enqueue_style( self::HANDLE, AGENT_MOD_URL . 'build/admin-chat/style-index.css', ['wp-components'], $asset['version'] ); $defaultModel = $this->settingsService->getDefaultModel(); wp_localize_script( self::HANDLE, 'agentModChat', [ 'restPath' => Constants::REST_NAMESPACE . '/chat', 'restNamespace' => Constants::REST_NAMESPACE, 'connectorsUrl' => SetupController::pageUrl('provider'), 'defaultAgent' => [ 'id' => null, 'name' => __('AgentMod Assistant', 'agent-mod'), 'description' => __('Uses the AgentMod settings configuration.', 'agent-mod'), 'avatar' => AGENT_MOD_URL . 'includes/Presentation/Admin/Assets/img/agent_mod_colored_icon.png', ], 'attachments' => [ 'maxBytes' => $this->settingsService->getAttachmentMaxBytes(), 'maxCount' => $this->settingsService->getAttachmentMaxCount(), 'mimeTypes' => $this->settingsService->getAttachmentMimeTypes(), ], 'defaults' => [ 'siteContextEnabled' => $this->settingsService->isSiteContextEnabled(), 'abilitySource' => $this->settingsService->getAbilitySource(), 'selectedAbilities' => $this->settingsService->getAllowedAbilitiesDetailed(), // Split into two keys so the model picker can pre-select the // pair without re-parsing the stored ":". 'defaultProvider' => $defaultModel['provider'], 'defaultModel' => $defaultModel['model'], ], 'presetPrompts' => $this->settingsService->getPresetPrompts(), 'strings' => [ 'title' => __('AgentMod Chat', 'agent-mod'), 'placeholder' => __('Type your message…', 'agent-mod'), 'send' => __('Send', 'agent-mod'), 'stop' => __('Stop', 'agent-mod'), 'error' => __('An unexpected error occurred.', 'agent-mod'), 'attach' => __('Attach files', 'agent-mod'), 'removeAttachment' => __('Remove attachment', 'agent-mod'), /* translators: %s: file name. */ 'fileTooLarge' => __('"%s" is too large.', 'agent-mod'), /* translators: %s: file name. */ 'fileTypeNotAllowed' => __('"%s" is not an allowed file type.', 'agent-mod'), /* translators: %d: maximum number of files allowed. */ 'tooManyFiles' => __('You can attach up to %d files.', 'agent-mod'), ], ] ); } /** * Renders the React root container in the admin footer. * * @return void * @since 1.0.0 */ public function renderRoot(): void { if (! current_user_can('manage_options')) { return; } echo '
'; } }