| 1 |
<?php |
| 2 |
/** |
| 3 |
* OpenStation — Agents: WP Explorer integration. |
| 4 |
* |
| 5 |
* Adds the "Agents" entity to the WP Explorer window (via the |
| 6 |
* `openstation_my_wordpress_entities` filter) and ships the agents |
| 7 |
* section config on the window's `config` payload (via |
| 8 |
* `openstation_my_wordpress_window_args`). The bundle side registers |
| 9 |
* the `agent` entity-kind renderer. |
| 10 |
* |
| 11 |
* This file loads regardless of the `agents` extended option (see |
| 12 |
* bootstrap.php) so the section is always discoverable. While the flag |
| 13 |
* is off the config carries `enabled => false` and the renderer paints |
| 14 |
* the section read-only — no REST call is attempted, because the |
| 15 |
* routes are not registered. It also carries `preview`, the cast the |
| 16 |
* site would get, read straight from `default-definitions.php`. |
| 17 |
* |
| 18 |
* @package OpenStation |
| 19 |
*/ |
| 20 |
|
| 21 |
defined( 'ABSPATH' ) || exit; |
| 22 |
|
| 23 |
/** |
| 24 |
* The roster as data. Deliberately not `defaults.php`, which registers |
| 25 |
* a seeder at file scope and needs the whole agents module behind it: |
| 26 |
* this file runs with the feature flag off, where none of that exists. |
| 27 |
*/ |
| 28 |
require_once __DIR__ . '/default-definitions.php'; |
| 29 |
|
| 30 |
/** |
| 31 |
* Append the Agents entity to WP Explorer's entity list. |
| 32 |
* |
| 33 |
* @param array $entities Existing entity descriptors. |
| 34 |
* @return array |
| 35 |
*/ |
| 36 |
function openstation_agents_my_wordpress_entity( $entities ) { |
| 37 |
if ( ! is_array( $entities ) || ! openstation_agents_user_can_read() ) { |
| 38 |
return $entities; |
| 39 |
} |
| 40 |
|
| 41 |
$entities[] = array( |
| 42 |
'id' => 'agents', |
| 43 |
'label' => __( 'Agents', 'desktop-mode' ), |
| 44 |
'icon' => openstation_agent_avatar_url(), |
| 45 |
'restPath' => 'desktop-mode/v1/agents', |
| 46 |
'kind' => 'agent', |
| 47 |
// The section is listed even with the feature off, so it can |
| 48 |
// render its own "disabled" preview and say how to enable it. |
| 49 |
// The REST route is NOT registered in that state, so anything |
| 50 |
// that probes `restPath` gets a 404 — and because the count |
| 51 |
// probe is a tracked fetch attributed to the window, the title |
| 52 |
// bar painted it as "Not saved. Request failed (HTTP 404)" on |
| 53 |
// every open, in the default install state. Clients skip the |
| 54 |
// probe when this is false. |
| 55 |
'enabled' => openstation_agents_enabled(), |
| 56 |
); |
| 57 |
|
| 58 |
return $entities; |
| 59 |
} |
| 60 |
add_filter( 'openstation_my_wordpress_entities', 'openstation_agents_my_wordpress_entity' ); |
| 61 |
|
| 62 |
/** |
| 63 |
* The cast a site would get, for the flag-off state. |
| 64 |
* |
| 65 |
* A site that has never switched Agents on has no agents: `defaults.php` |
| 66 |
* only loads inside the flag, so the seeder has never run. That used to |
| 67 |
* make the off-state a paragraph of explanatory text, which is a weak |
| 68 |
* argument for turning something on. These are the same five cards the |
| 69 |
* grid draws once the flag is on, greyed and inert above the button |
| 70 |
* that flips it. Seeing who you would get is the argument. |
| 71 |
* |
| 72 |
* Only what a card draws: a name, a voice, what it is good for, and a |
| 73 |
* face. The instructions and the abilities are the bulk of a |
| 74 |
* definition and none of them are on screen here, so they stay out of |
| 75 |
* a payload that ships on every WP Explorer window open. |
| 76 |
* |
| 77 |
* Faces go through `openstation_mio_narrow_look()`, the same narrowing |
| 78 |
* the store applies when an agent saves one, so a preview cannot show |
| 79 |
* a face the seeder would then clamp into a different one. |
| 80 |
* |
| 81 |
* The role arrives already translated. A real card reads its label out |
| 82 |
* of the `/agents/roles` catalogue, and that route does not exist while |
| 83 |
* the flag is off — left to the client the badge would fall back to the |
| 84 |
* raw slug and five preview cards would say "editor" in English on a |
| 85 |
* Spanish site. |
| 86 |
* |
| 87 |
* @return array<int, array<string, mixed>> |
| 88 |
*/ |
| 89 |
function openstation_agents_preview_cast() { |
| 90 |
$names = wp_roles()->get_names(); |
| 91 |
$cast = array(); |
| 92 |
|
| 93 |
foreach ( openstation_agents_default_definitions() as $definition ) { |
| 94 |
$role = $definition['role']; |
| 95 |
|
| 96 |
$cast[] = array( |
| 97 |
'name' => $definition['name'], |
| 98 |
'vibes' => $definition['vibes'], |
| 99 |
'description' => $definition['description'], |
| 100 |
'role' => $role, |
| 101 |
'roleLabel' => isset( $names[ $role ] ) ? translate_user_role( $names[ $role ] ) : $role, |
| 102 |
'face' => openstation_mio_narrow_look( $definition['face'] ), |
| 103 |
); |
| 104 |
} |
| 105 |
|
| 106 |
return $cast; |
| 107 |
} |
| 108 |
|
| 109 |
/** |
| 110 |
* Ship the agents section config on the WP Explorer window config. |
| 111 |
* |
| 112 |
* `enabled` mirrors the `agents` extended option. When it is false the |
| 113 |
* section still renders — every control disabled, nothing fetched — |
| 114 |
* and offers `canEnable` users a way into the Features tab that turns |
| 115 |
* the framework on. `canManage` / `canInvoke` stay the raw capability |
| 116 |
* answers so that shell renders the same controls it would when the |
| 117 |
* flag is on, just inert; the real gate is that the REST routes do not |
| 118 |
* exist while off. |
| 119 |
* |
| 120 |
* `aiAvailable` is the cheap structural check (WP 7.0 AI Client + |
| 121 |
* Abilities API present); whether a connector is actually configured |
| 122 |
* is probed live by the renderer against `aiStatusUrl`, mirroring the |
| 123 |
* OS Settings Features tab, so a freshly configured connector is |
| 124 |
* picked up without a reload. |
| 125 |
* |
| 126 |
* `preview` is only sent while the flag is off, which is the only |
| 127 |
* state that draws it: once Agents is on, the real cast has been |
| 128 |
* seeded and the grid renders that instead. |
| 129 |
* |
| 130 |
* @param array $window_args Args passed to `openstation_register_window()`. |
| 131 |
* @return array |
| 132 |
*/ |
| 133 |
function openstation_agents_my_wordpress_window_args( $window_args ) { |
| 134 |
if ( ! is_array( $window_args ) || ! openstation_agents_user_can_read() ) { |
| 135 |
return $window_args; |
| 136 |
} |
| 137 |
|
| 138 |
if ( ! isset( $window_args['config'] ) || ! is_array( $window_args['config'] ) ) { |
| 139 |
$window_args['config'] = array(); |
| 140 |
} |
| 141 |
|
| 142 |
$enabled = openstation_agents_enabled(); |
| 143 |
|
| 144 |
$window_args['config']['agents'] = array( |
| 145 |
'enabled' => $enabled, |
| 146 |
'canEnable' => current_user_can( 'manage_options' ), |
| 147 |
'canManage' => openstation_agents_user_can_manage(), |
| 148 |
'canInvoke' => openstation_agents_user_can_invoke(), |
| 149 |
'aiAvailable' => function_exists( 'openstation_ai_is_available' ) && openstation_ai_is_available(), |
| 150 |
'aiStatusUrl' => esc_url_raw( rest_url( 'desktop-mode/v1/ai/status' ) ), |
| 151 |
'connectorsUrl' => esc_url_raw( admin_url( 'options-connectors.php' ) ), |
| 152 |
'runWindowId' => 'desktop-mode-agent-run', |
| 153 |
); |
| 154 |
|
| 155 |
if ( ! $enabled ) { |
| 156 |
$window_args['config']['agents']['preview'] = openstation_agents_preview_cast(); |
| 157 |
} |
| 158 |
|
| 159 |
return $window_args; |
| 160 |
} |
| 161 |
add_filter( 'openstation_my_wordpress_window_args', 'openstation_agents_my_wordpress_window_args' ); |
| 162 |
|