File manager - Edit - /home/proidvn/site.proid.vn/wp-content/plugins/novamira/includes/instructions-admin.php
Back
<?php // SPDX-FileCopyrightText: 2026 Ovation S.r.l. <dev@novamira.ai> // SPDX-License-Identifier: AGPL-3.0-or-later declare(strict_types=1); namespace Novamira\Context; if (!defined('ABSPATH')) { exit(); } /** * Admin page for site-level context shown to connected agents. The saved * content is prepended to the Novamira discover-abilities instructions, while * the read-only preview shows the system instructions without that user layer. */ const INSTRUCTIONS_ENABLED_OPTION = 'novamira_instructions_enabled'; const INSTRUCTIONS_CONTENT_OPTION = 'novamira_instructions_content'; const LEGACY_PRO_INSTRUCTIONS_ENABLED_OPTION = 'nvp_instructions_enabled'; const LEGACY_PRO_INSTRUCTIONS_CONTENT_OPTION = 'nvp_instructions_content'; const OPTION_MISSING = '__novamira_option_missing__'; function context_page_slug(): string { return 'novamira-context'; } /** @param array<string, scalar> $query */ function context_page_url(array $query = []): string { return add_query_arg(array_merge(['page' => context_page_slug()], $query), admin_url('admin.php')); } function instructions_enabled_option_name(): string { return INSTRUCTIONS_ENABLED_OPTION; } function instructions_content_option_name(): string { return INSTRUCTIONS_CONTENT_OPTION; } function instructions_legacy_enabled_option_name(): string { return LEGACY_PRO_INSTRUCTIONS_ENABLED_OPTION; } function instructions_legacy_content_option_name(): string { return LEGACY_PRO_INSTRUCTIONS_CONTENT_OPTION; } function instructions_read_option_with_legacy(string $option_name, string $legacy_option_name, mixed $default): mixed { /** @var mixed $value */ $value = get_option($option_name, default_value: OPTION_MISSING); if ($value !== OPTION_MISSING) { return $value; } /** @var mixed $legacy_value */ $legacy_value = get_option($legacy_option_name, default_value: OPTION_MISSING); if ($legacy_value !== OPTION_MISSING) { return $legacy_value; } return $default; } function instructions_update_enabled_value(string $value): void { update_option(instructions_enabled_option_name(), $value); update_option(instructions_legacy_enabled_option_name(), $value); } function instructions_update_content(string $content): void { update_option(instructions_content_option_name(), $content); update_option(instructions_legacy_content_option_name(), $content); } function legacy_pro_context_loaded(): bool { return ( function_exists('\\Novamira\\Pro\\instructions_get_content') && function_exists('\\Novamira\\Pro\\instructions_is_enabled') ); } function instructions_is_enabled(): bool { return filter_var( instructions_read_option_with_legacy( option_name: instructions_enabled_option_name(), legacy_option_name: instructions_legacy_enabled_option_name(), default: true, ), FILTER_VALIDATE_BOOLEAN, ); } function instructions_get_content(): string { /** @var mixed $raw */ $raw = instructions_read_option_with_legacy( option_name: instructions_content_option_name(), legacy_option_name: instructions_legacy_content_option_name(), default: '', ); return is_string($raw) ? $raw : ''; } function instructions_custom_injection_suppression_state(string $action = 'read'): bool { static $suppressed = false; $previous = $suppressed; if ($action === 'suppress') { $suppressed = true; } if ($action === 'restore_enabled') { $suppressed = true; } if ($action === 'restore_disabled') { $suppressed = false; } return $previous; } function instructions_custom_injection_suppressed(): bool { return instructions_custom_injection_suppression_state(); } function instructions_post_string(string $key): string { $raw = $_POST[$key] ?? ''; if (!is_string($raw)) { return ''; } return wp_unslash($raw); } function register_context_menu(): void { if (!defined('NOVAMIRA_VERSION')) { return; } // Stay out while a Novamira Pro that still manages custom instructions is // active: that Pro owns the instructions UI (its "Memory & Instructions" // page) until it is removed or updated to a version that hands context to // the base. The base then takes over automatically — see // legacy_pro_context_loaded(). if (legacy_pro_context_loaded()) { return; } add_submenu_page( parent_slug: 'novamira-connect', page_title: __('Novamira Context', domain: 'novamira'), menu_title: __('Context', domain: 'novamira'), capability: \novamira_manage_capability(), menu_slug: context_page_slug(), callback: __NAMESPACE__ . '\\render_context_page', ); } /** @return array{type:string,message:string}|null */ function context_handle_post(): ?array { if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') { return null; } $action = instructions_post_string('novamira_context_action'); if (!in_array($action, ['toggle_context', 'save_context'], strict: true)) { return null; } check_admin_referer('novamira_context'); if (!\novamira_current_user_can_manage()) { wp_die(esc_html__('You are not allowed to manage context.', domain: 'novamira')); } if ($action === 'toggle_context') { return instructions_handle_toggle(); } return instructions_handle_save(); } /** @return array{type:string,message:string} */ function instructions_handle_toggle(): array { $enable = instructions_post_string('instructions_enabled') === '1'; // Store as string to avoid WordPress's update_option short-circuit when the // option doesn't yet exist: get_option returns false as the implicit old // value, and update_option(name, false) bails out before add_option runs. instructions_update_enabled_value($enable ? '1' : '0'); return [ 'type' => 'success', 'message' => $enable ? __('User context enabled for agents.', domain: 'novamira') : __('User context disabled for agents. Content is kept.', domain: 'novamira'), ]; } /** @return array{type:string,message:string} */ function instructions_handle_save(): array { $content = instructions_post_string('instructions_content'); instructions_update_content($content); return [ 'type' => 'success', 'message' => __('User context saved.', domain: 'novamira'), ]; } function context_system_instructions_preview(): string { if (!function_exists('novamira_build_server_instructions')) { return __('System instructions are unavailable until the base Novamira plugin has loaded.', domain: 'novamira'); } $previous = instructions_custom_injection_suppression_state(action: 'suppress'); try { return (string) apply_filters( 'novamira_discover_abilities_instructions', \novamira_build_server_instructions(), ); } finally { instructions_custom_injection_suppression_state(action: $previous ? 'restore_enabled' : 'restore_disabled'); } } function context_system_instructions_excerpt(string $instructions, int $line_count = 6): string { if ($line_count < 1) { return '...'; } $normalized = preg_replace(pattern: '/\r\n?/', replacement: "\n", subject: $instructions) ?? $instructions; $lines = explode(separator: "\n", string: ltrim($normalized, characters: "\n")); if (count($lines) <= $line_count) { return implode(separator: "\n", array: $lines); } $excerpt = array_slice($lines, offset: 0, length: $line_count); $excerpt[] = '...'; return implode(separator: "\n", array: $excerpt); } function render_context_page(): void { if (!\novamira_current_user_can_manage()) { return; } $notice = context_handle_post(); if (function_exists('novamira_render_admin_header')) { novamira_render_admin_header(); } ?> <div class="wrap"> <h1 class="wp-heading-inline"><?php esc_html_e('Context', domain: 'novamira'); ?></h1> <hr class="wp-header-end"> <p class="description novamira-context-intro"><?php esc_html_e( 'Review the system instructions connected agents receive, then add site-specific context that should apply in every conversation.', domain: 'novamira', ); ?></p> <?php render_context_notice($notice); ?> <?php render_context_styles(); ?> <?php render_context_system_section(); ?> <?php render_user_context_section(); ?> <?php do_action('novamira_context_page_sections'); ?> </div> <?php } function render_context_styles(): void { ?> <style> .novamira-context-intro { margin-top:8px; max-width:800px; } .novamira-context-section { margin-top:24px; max-width:1100px; } .novamira-context-section h2 { margin-bottom:4px; font-size:16px; } .novamira-context-panel { background:#fff; border:1px solid #dcdcde; border-radius:12px; padding:16px 20px; margin-top:12px; } .novamira-context-status { display:flex; align-items:center; justify-content:space-between; gap:16px; flex-wrap:wrap; } .novamira-context-status .status-text { display:flex; align-items:center; gap:10px; } .novamira-context-status .status-pill { display:inline-flex; align-items:center; gap:6px; padding:4px 12px; border-radius:999px; font-weight:600; font-size:12px; } .novamira-context-status .status-pill.is-on { background:#edf7ed; color:#0a5c1b; } .novamira-context-status .status-pill.is-off { background:#fcf0f1; color:#8a2424; } .novamira-context-status .status-hint { color:#50575e; margin:6px 0 0; max-width:680px; } .novamira-system-box summary { cursor:pointer; font-weight:600; } .novamira-system-preview-wrap { position:relative; margin-top:12px; } .novamira-system-preview { box-sizing:border-box; width:100%; max-height:none; overflow:auto; margin:0; padding:14px 16px; background:#f6f7f7; border:1px solid #dcdcde; border-radius:8px; white-space:pre-wrap; font-family:ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size:12px; line-height:1.55; } .novamira-system-preview.is-excerpt { margin-top:12px; } .novamira-system-details[open] + .novamira-system-preview.is-excerpt { display:none; } .novamira-context-guidance { margin-top:12px; color:#1d2327; } .novamira-context-guidance ul { list-style:disc; margin-left:20px; max-width:780px; } .novamira-context-guidance li { margin:4px 0; } .novamira-context-form { margin-top:12px; } .novamira-context-form textarea { font-family:ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; font-size:13px; } </style> <?php } function render_context_system_section(): void { $preview = context_system_instructions_preview(); $excerpt = context_system_instructions_excerpt($preview); ?> <section class="novamira-context-section" aria-labelledby="novamira-system-context-heading"> <h2 id="novamira-system-context-heading"><?php esc_html_e('System context', domain: 'novamira'); ?></h2> <p class="description"><?php esc_html_e( 'Read-only instructions Novamira generates for this site, adapting them to the plugins you have active. Shown here for visibility and not editable from this page.', domain: 'novamira', ); ?></p> <div class="novamira-context-panel novamira-system-box"> <details class="novamira-system-details"> <summary><?php esc_html_e('Show full system context', domain: 'novamira'); ?></summary> <div class="novamira-system-preview-wrap" aria-label="<?php echo esc_attr__('Read-only system context preview', domain: 'novamira') ; ?>"> <pre class="novamira-system-preview is-full"><?php echo esc_html($preview); ?></pre> </div> </details> <pre class="novamira-system-preview is-excerpt"><?php echo esc_html($excerpt); ?></pre> </div> </section> <?php } function render_user_context_section(): void { $is_enabled = instructions_is_enabled(); $content = instructions_get_content(); $submit_value = $is_enabled ? '0' : '1'; $toggle_label = $is_enabled ? __('Disable user context', domain: 'novamira') : __('Enable user context', domain: 'novamira'); $toggle_class = $is_enabled ? 'button button-secondary' : 'button button-primary'; $status_class = $is_enabled ? 'is-on' : 'is-off'; $status_label = $is_enabled ? __('On', domain: 'novamira') : __('Off', domain: 'novamira'); $hint = $is_enabled ? __('User-added context is prepended to the system context shown to agents.', domain: 'novamira') : __( 'User-added context is hidden from agents. Content stays in place and is used again when you re-enable.', domain: 'novamira', ); $form_url = context_page_url(); ?> <section class="novamira-context-section" aria-labelledby="novamira-user-context-heading"> <h2 id="novamira-user-context-heading"><?php esc_html_e('User context', domain: 'novamira'); ?></h2> <p class="description"><?php esc_html_e( 'Additional instructions provided by this site owner for all connected agents.', domain: 'novamira', ); ?></p> <div class="novamira-context-panel novamira-context-status"> <div> <div class="status-text"> <strong><?php esc_html_e('User context:', domain: 'novamira'); ?></strong> <span class="status-pill <?php echo esc_attr($status_class); ?>"><?php echo esc_html($status_label); ?></span> </div> <p class="status-hint"><?php echo esc_html($hint); ?></p> </div> <form method="post" action="<?php echo esc_url($form_url); ?>"> <?php wp_nonce_field('novamira_context'); ?> <input type="hidden" name="novamira_context_action" value="toggle_context"> <input type="hidden" name="instructions_enabled" value="<?php echo esc_attr($submit_value); ?>"> <button type="submit" class="<?php echo esc_attr($toggle_class); ?>"><?php echo esc_html($toggle_label) ; ?></button> </form> </div> <div class="novamira-context-panel novamira-context-guidance"> <p style="margin-top:0;"><?php esc_html_e( 'Stable context agents should apply on this site without asking again.', domain: 'novamira', ); ?></p> <ul> <li><?php esc_html_e( 'Site goals, brand voice, audience, and naming conventions.', domain: 'novamira', ); ?></li> <li><?php esc_html_e( 'Constraints: what to avoid, what needs approval, and preferred workflows.', domain: 'novamira', ); ?></li> </ul> <p style="margin-bottom:0;"><?php esc_html_e( 'No passwords, API keys, private data, or one-off notes. Keep it stable and site-wide.', domain: 'novamira', ); ?></p> </div> <form method="post" action="<?php echo esc_url($form_url); ?>" class="novamira-context-form"> <?php wp_nonce_field('novamira_context'); ?> <input type="hidden" name="novamira_context_action" value="save_context"> <label for="instructions_content" class="screen-reader-text"><?php esc_html_e( 'User context', domain: 'novamira', ); ?></label> <textarea id="instructions_content" name="instructions_content" rows="14" class="large-text code" placeholder="<?php echo esc_attr__( 'Write site-level context for connected agents. Markdown is supported.', domain: 'novamira', ) ; ?>" ><?php echo esc_textarea($content); ?></textarea> <p style="margin-top:8px;"> <button type="submit" class="button button-primary"><?php esc_html_e( 'Save context', domain: 'novamira', ); ?></button> </p> </form> </section> <?php } /** @param array{type:string,message:string}|null $notice */ function render_context_notice(?array $notice): void { if ($notice === null) { return; } $type = in_array($notice['type'], ['success', 'warning', 'error', 'info'], strict: true) ? $notice['type'] : 'info'; ?> <div class="notice notice-<?php echo esc_attr($type); ?> is-dismissible"><p><?php echo esc_html($notice['message']) ; ?></p></div> <?php } function boot_context_admin(): void { add_action('admin_menu', callback: __NAMESPACE__ . '\\register_context_menu', priority: 12); }
| ver. 1.4 |
Github
|
.
| PHP 8.0.30 | Generation time: 0.12 |
proxy
|
phpinfo
|
Settings