Skip to content

Commit 4ad17b2

Browse files
authored
wip: gate provider trace behind WP_DEBUG (#1162)
1 parent a7fd4d5 commit 4ad17b2

6 files changed

Lines changed: 83 additions & 12 deletions

File tree

includes/Admin/UnifiedAdminMenu.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,9 @@ function () {
313313
'menuItems' => self::getMenuItems(),
314314
'connectorsUrl' => self::getConnectorsUrl(),
315315
'connectorsAvailable' => self::hasNativeConnectorsPage() || self::hasGutenbergConnectorsPage() ? '1' : '',
316+
// Provider trace is a debug-only feature. The JS settings page reads
317+
// this flag to show or hide the Provider Trace tab.
318+
'wpDebug' => defined( 'WP_DEBUG' ) && WP_DEBUG ? '1' : '',
316319
// Feature flags — mirrors Features::all() so JS can gate UI sections
317320
// without waiting for the /settings REST response.
318321
'features' => Features::all(),

includes/Bootstrap/CliHandler.php

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use GratisAiAgent\CLI\BenchmarkCommand;
1414
use GratisAiAgent\CLI\CliCommand;
1515
use GratisAiAgent\CLI\TraceCommand;
16+
use GratisAiAgent\Models\ProviderTrace;
1617
use WP_CLI;
1718
use XWP\DI\Decorators\Action;
1819
use XWP\DI\Decorators\Handler;
@@ -44,16 +45,24 @@
4445
final class CliHandler {
4546

4647
/**
47-
* Command-to-class map used to derive both primary and alias registrations.
48+
* Commands always registered regardless of WP_DEBUG.
4849
*
4950
* @var array<string,class-string>
5051
*/
5152
private const COMMANDS = array(
5253
'prompt' => CliCommand::class,
53-
'trace' => TraceCommand::class,
5454
'benchmark' => BenchmarkCommand::class,
5555
);
5656

57+
/**
58+
* Commands only registered when WP_DEBUG is active.
59+
*
60+
* @var array<string,class-string>
61+
*/
62+
private const DEBUG_COMMANDS = array(
63+
'trace' => TraceCommand::class,
64+
);
65+
5766
/**
5867
* Primary and alias root namespaces under which every subcommand is exposed.
5968
*
@@ -67,11 +76,20 @@ final class CliHandler {
6776
* Hooked on `cli_init` — guaranteed to fire only when WP-CLI is active,
6877
* which removes the need for the legacy `defined('WP_CLI')` guard that
6978
* used to live in the plugin bootstrap file.
79+
*
80+
* Debug-only commands (e.g. `trace`) are only registered when WP_DEBUG
81+
* is defined and truthy, matching the REST and UI availability gates.
7082
*/
7183
#[Action( tag: 'cli_init', priority: 10 )]
7284
public function register_commands(): void {
85+
$commands = self::COMMANDS;
86+
87+
if ( ProviderTrace::is_debug_mode() ) {
88+
$commands = array_merge( $commands, self::DEBUG_COMMANDS );
89+
}
90+
7391
foreach ( self::NAMESPACES as $ns ) {
74-
foreach ( self::COMMANDS as $sub => $class ) {
92+
foreach ( $commands as $sub => $class ) {
7593
WP_CLI::add_command( "{$ns} {$sub}", $class );
7694
}
7795
}

includes/Bootstrap/HttpTraceHandler.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
namespace GratisAiAgent\Bootstrap;
2020

2121
use GratisAiAgent\Core\ProviderTraceLogger;
22+
use GratisAiAgent\Models\ProviderTrace;
2223
use XWP\DI\Decorators\Filter;
2324
use XWP\DI\Decorators\Handler;
2425

@@ -32,6 +33,10 @@
3233
* CTX_GLOBAL ensures the filters are active in every request context — AI
3334
* calls can originate from admin (manual runs), REST (webhook triggers), CLI,
3435
* and cron (scheduled tasks).
36+
*
37+
* Both filter callbacks are no-ops when WP_DEBUG is not active. The DI
38+
* container always instantiates this handler, but the actual recording never
39+
* happens on production sites where WP_DEBUG is false or undefined.
3540
*/
3641
#[Handler(
3742
container: 'gratis-ai-agent',
@@ -44,7 +49,8 @@ final class HttpTraceHandler {
4449
* Capture outgoing request details before the HTTP call is made.
4550
*
4651
* Returns `$preempt` unchanged — this filter is used only for its
47-
* side-effect of recording in-flight request metadata.
52+
* side-effect of recording in-flight request metadata. No-op when
53+
* WP_DEBUG is not active.
4854
*
4955
* @param false|array<string,mixed>|\WP_Error $preempt A preemptive return value. Default false.
5056
* @param array<string,mixed> $parsed_args HTTP request arguments.
@@ -53,14 +59,18 @@ final class HttpTraceHandler {
5359
*/
5460
#[Filter( tag: 'pre_http_request', priority: 10 )]
5561
public function on_pre_http_request( mixed $preempt, array $parsed_args, string $url ): mixed {
62+
if ( ! ProviderTrace::is_debug_mode() ) {
63+
return $preempt;
64+
}
5665
return ProviderTraceLogger::on_pre_http_request( $preempt, $parsed_args, $url );
5766
}
5867

5968
/**
6069
* Capture response details and write a trace record.
6170
*
6271
* Returns `$response` unchanged — this filter is used only for its
63-
* side-effect of persisting the completed trace row.
72+
* side-effect of persisting the completed trace row. No-op when
73+
* WP_DEBUG is not active.
6474
*
6575
* @param array<string,mixed> $response HTTP response array.
6676
* @param array<string,mixed> $parsed_args HTTP request arguments.
@@ -69,6 +79,9 @@ public function on_pre_http_request( mixed $preempt, array $parsed_args, string
6979
*/
7080
#[Filter( tag: 'http_response', priority: 10 )]
7181
public function on_http_response( array $response, array $parsed_args, string $url ): array {
82+
if ( ! ProviderTrace::is_debug_mode() ) {
83+
return $response;
84+
}
7285
return ProviderTraceLogger::on_http_response( $response, $parsed_args, $url );
7386
}
7487
}

includes/Models/ProviderTrace.php

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,18 +74,40 @@ public static function get_schema( string $charset ): string {
7474
) {$charset};";
7575
}
7676

77+
/**
78+
* Whether the provider trace feature is available on this installation.
79+
*
80+
* Provider tracing is a debug-only feature. It captures raw HTTP request
81+
* and response bodies from LLM provider calls, which may contain prompt
82+
* content and model outputs. Availability is therefore gated on WP_DEBUG
83+
* so the feature is never active on production sites.
84+
*
85+
* @return bool True only when the WP_DEBUG constant is defined and truthy.
86+
*/
87+
public static function is_debug_mode(): bool {
88+
return defined( 'WP_DEBUG' ) && (bool) WP_DEBUG;
89+
}
90+
7791
/**
7892
* Check whether provider tracing is enabled.
7993
*
80-
* Checks the filter first, then the option.
94+
* Returns false immediately when WP_DEBUG is not active — tracing is a
95+
* debug-only feature and must never run on production. When WP_DEBUG is
96+
* set, checks the filter first, then the stored option.
8197
*
8298
* @return bool
8399
*/
84100
public static function is_enabled(): bool {
101+
// Provider trace is a debug-only feature.
102+
if ( ! self::is_debug_mode() ) {
103+
return false;
104+
}
105+
85106
/**
86107
* Filter to enable/disable provider trace logging.
87108
*
88109
* Allows enabling tracing environmentally without touching settings.
110+
* Only evaluated when WP_DEBUG is active.
89111
*
90112
* @param bool|null $enabled Null to defer to the option, true/false to override.
91113
*/

includes/REST/TraceController.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,18 @@
4545
final class TraceController extends XWP_REST_Controller {
4646

4747
/**
48-
* Permission check — admin only.
48+
* Permission check — admin only, and only when WP_DEBUG is active.
49+
*
50+
* Provider tracing is a debug-only feature. The REST endpoints are
51+
* unavailable (return 403) on any site where WP_DEBUG is not defined
52+
* or is false, regardless of the user's role.
4953
*
5054
* @return bool
5155
*/
5256
public function check_permission(): bool {
57+
if ( ! ProviderTrace::is_debug_mode() ) {
58+
return false;
59+
}
5360
return current_user_can( 'manage_options' );
5461
}
5562

src/settings-page/settings-app.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,9 @@ export default function SettingsApp() {
361361
( p ) => p.id === local.default_provider
362362
);
363363

364+
// Provider trace is a debug-only feature — only show the tab when
365+
// WP_DEBUG is active (communicated from PHP via gratisAiAgentData.wpDebug).
366+
const isWpDebug = !! window.gratisAiAgentData?.wpDebug;
364367
// Feature flags injected by PHP (UnifiedAdminMenu::enqueueAssets).
365368
// Fall back to all-enabled when the global is absent (e.g. unit tests).
366369
const features = window.gratisAiAgentData?.features ?? {
@@ -415,11 +418,16 @@ export default function SettingsApp() {
415418
title: __( 'Usage', 'gratis-ai-agent' ),
416419
className: 'gratis-ai-agent-settings-tab',
417420
},
418-
{
419-
name: 'provider-trace',
420-
title: __( 'Provider Trace', 'gratis-ai-agent' ),
421-
className: 'gratis-ai-agent-settings-tab',
422-
},
421+
// Only visible when WP_DEBUG is active.
422+
...( isWpDebug
423+
? [
424+
{
425+
name: 'provider-trace',
426+
title: __( 'Provider Trace', 'gratis-ai-agent' ),
427+
className: 'gratis-ai-agent-settings-tab',
428+
},
429+
]
430+
: [] ),
423431
{
424432
name: 'advanced',
425433
title: __( 'Advanced', 'gratis-ai-agent' ),

0 commit comments

Comments
 (0)