PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 0.9.6
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v0.9.6
1.1.10 1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.1 1.0.0 0.9.8 0.9.7 0.9.6 0.9.4 0.9.5 0.9.3 0.9.2 0.9.1 0.9.0 0.8.9 0.8.8 0.8.7 All 34 releases
desktop-mode / includes / ai-copilot / jobs.php

jobs.php in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 0.9.6, at includes/ai-copilot/jobs.php

127 lines 4.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Desktop Mode — AI Copilot WP-Cron jobs.
4 *
5 * Registers the async comment-analysis hook that scores a comment for
6 * spam/harmful content and stores the verdict in comment meta. The job is
7 * scheduled by the Comments-window moderation feature (which is opt-in and
8 * off by default) with a short delay so it runs outside the HTTP request that
9 * triggered the comment.
10 *
11 * Generation routes through the WordPress AI Client (`wp_ai_client_prompt()`),
12 * which sources credentials from Settings → Connectors — the copilot never
13 * handles an API key.
14 *
15 * Hook name:
16 * desktop_mode_ai_analyze_comment ($comment_id, $user_id)
17 *
18 * @package WPDesktopMode
19 */
20
21 defined( 'ABSPATH' ) || exit;
22
23 // ---------------------------------------------------------------------------
24 // Job: comment
25 // ---------------------------------------------------------------------------
26
27 /**
28 * Analyzes a comment and stores the result in comment meta.
29 *
30 * @since 0.5.0
31 *
32 * @param int $comment_id The comment ID.
33 * @param int $user_id The user to attribute the request to.
34 */
35 function desktop_mode_ai_job_analyze_comment( $comment_id, $user_id ) {
36 $comment_id = (int) $comment_id;
37 $user_id = (int) $user_id;
38
39 // No usable text-generation provider is configured in Connectors — nothing
40 // to do. The scheduler already checks this, but the job runs async so we
41 // re-check to avoid emitting failed requests if the provider was removed.
42 if ( ! desktop_mode_ai_provider_configured() ) {
43 return;
44 }
45
46 $comment = get_comment( $comment_id );
47 if ( ! $comment instanceof WP_Comment ) {
48 return;
49 }
50
51 $result = desktop_mode_ai_analyze_comment_now( $comment, $user_id );
52
53 if ( is_wp_error( $result ) ) {
54 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
55 error_log( '[WP Desktop Mode AI] Comment ' . $comment_id . ' analysis failed: ' . $result->get_error_message() );
56 return;
57 }
58
59 desktop_mode_ai_save_meta( 'comment', $comment_id, $result );
60
61 /**
62 * Fires after a comment has been successfully analyzed by the AI copilot.
63 *
64 * The `$result` array always contains `topic`, `ai_summary`, `harmful`,
65 * and `spam`. Downstream plugins (e.g. a moderation helper) can act on
66 * `harmful` or `spam` here rather than polling meta.
67 *
68 * @since 0.5.0
69 *
70 * @param int $comment_id The comment ID.
71 * @param array $result The structured analysis result.
72 * @param WP_Comment $comment The comment object.
73 */
74 do_action( 'desktop_mode_ai_comment_analyzed', $comment_id, $result, $comment );
75 }
76 add_action( 'desktop_mode_ai_analyze_comment', 'desktop_mode_ai_job_analyze_comment', 10, 2 );
77
78 /**
79 * Runs the structured comment analysis through the AI Client.
80 *
81 * Converts the chat-style prompt from {@see desktop_mode_ai_messages_for_comment()}
82 * into a system instruction + user prompt, requests JSON constrained to the
83 * comment schema, and decodes the result.
84 *
85 * @since 0.9.4
86 *
87 * @param WP_Comment $comment The comment to analyze.
88 * @param int $user_id Requesting user id. Currently unused — the builder
89 * is built from the prompt alone and the provider
90 * comes from Connectors; retained for signature
91 * stability and future attribution.
92 * @return array|WP_Error Structured `{ topic, ai_summary, harmful, spam }` or an error.
93 */
94 function desktop_mode_ai_analyze_comment_now( WP_Comment $comment, $user_id ) {
95 $messages = desktop_mode_ai_messages_for_comment( $comment );
96 $schema = desktop_mode_ai_schema_comment();
97
98 $system = '';
99 $prompt = '';
100 foreach ( $messages as $message ) {
101 $role = isset( $message['role'] ) ? $message['role'] : '';
102 if ( 'system' === $role ) {
103 $system = (string) $message['content'];
104 } elseif ( 'user' === $role ) {
105 $prompt = (string) $message['content'];
106 }
107 }
108
109 $builder = wp_ai_client_prompt( $prompt );
110 if ( '' !== $system ) {
111 $builder = $builder->using_system_instruction( $system );
112 }
113 // Provider + model are chosen by the Core AI Client; Desktop Mode pins neither.
114
115 $json = $builder->as_json_response( $schema )->generate_text();
116 if ( is_wp_error( $json ) ) {
117 return $json;
118 }
119
120 $result = json_decode( (string) $json, true );
121 if ( ! is_array( $result ) ) {
122 return new WP_Error( 'desktop_mode_ai_bad_json', 'The AI response was not valid JSON.' );
123 }
124
125 return $result;
126 }
127