PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.11
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.11
1.1.11 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 All 35 releases
← All changes | includes/widgets/widget-drafts.php +69 -5 1.1.101.1.11 View file →
@@ -334,13 +334,9 @@
334 334 $json = new WP_Error( 'openstation_ai_failed', $e->getMessage() );
335 335 }
336 336
337 337 if ( is_wp_error( $json ) ) {
338 - return new WP_Error(
339 - 'openstation_ai_failed',
340 - $json->get_error_message(),
341 - array( 'status' => 502 )
342 - );
338 + return openstation_drafts_ai_failure( $json );
343 339 }
344 340
345 341 $data = json_decode( (string) $json, true );
346 342 if ( ! is_array( $data ) ) {
@@ -375,8 +371,76 @@
375 371 */
376 372 $suggestions = (array) apply_filters( 'openstation_drafts_ai_suggestions', $suggestions, $post );
377 373
378 374 return new WP_REST_Response( $suggestions, 200 );
375 +}
376 +
377 +/**
378 + * Turn a failed generation into the route's error.
379 + *
380 + * The route answers 502 for every provider failure: the failure is the
381 + * upstream's, not the caller's, and a provider's own 401 or 403 passed
382 + * through as the REST status would read as "your WordPress session is
383 + * invalid" to every client on the page. What the caller needs in order to
384 + * say something useful goes into the error data instead:
385 + *
386 + * - `reason`: `quota` (out of credits or rate limited), `auth` (the site's
387 + * key was rejected), `unavailable` (the provider could not be reached or
388 + * answered 5xx) or `other`.
389 + * - `provider_status`: the provider's own HTTP status, or null when the
390 + * failure never reached the provider.
391 + * - `detail`: the provider's message, verbatim, for the console and logs.
392 + *
393 + * The top-level message says what happened in plain words. The Core AI
394 + * Client reports a rejected request as `prompt_client_error` /
395 + * `prompt_upstream_server_error` with the provider's status in
396 + * `data.status` and a message of the shape "Too Many Requests (429) -
397 + * <provider text>", which is why the provider text never reached the
398 + * widget as anything but that string.
399 + *
400 + * @param WP_Error $error Failed generation.
401 + * @return WP_Error
402 + */
403 +function openstation_drafts_ai_failure( WP_Error $error ) {
404 + $code = (string) $error->get_error_code();
405 + $data = $error->get_error_data();
406 + $detail = (string) $error->get_error_message();
407 +
408 + $provider_status = null;
409 + if ( in_array( $code, array( 'prompt_client_error', 'prompt_upstream_server_error' ), true )
410 + && is_array( $data ) && isset( $data['status'] ) ) {
411 + $provider_status = (int) $data['status'];
412 + }
413 +
414 + if ( 'prompt_network_error' === $code || ( null !== $provider_status && $provider_status >= 500 ) ) {
415 + $reason = 'unavailable';
416 + $message = __( 'The AI provider could not be reached. Try again in a moment.', 'desktop-mode' );
417 + } elseif ( in_array( $provider_status, array( 402, 429 ), true ) ) {
418 + $reason = 'quota';
419 + $message = __( 'The AI provider has no credits left or is rate limiting this site. Check its plan and billing, or try again later.', 'desktop-mode' );
420 + } elseif ( in_array( $provider_status, array( 401, 403 ), true ) ) {
421 + $reason = 'auth';
422 + $message = __( 'The AI provider rejected this site’s API key. Check the key in Settings → Connectors.', 'desktop-mode' );
423 + } elseif ( null === $provider_status && preg_match( '/quota|credits?\b|billing|rate limit/i', $detail ) ) {
424 + // A provider that failed without a status (the SDK threw instead of
425 + // answering) can still say it was the account, not the request.
426 + $reason = 'quota';
427 + $message = __( 'The AI provider has no credits left or is rate limiting this site. Check its plan and billing, or try again later.', 'desktop-mode' );
428 + } else {
429 + $reason = 'other';
430 + $message = __( 'The AI provider could not produce suggestions.', 'desktop-mode' );
431 + }
432 +
433 + return new WP_Error(
434 + 'openstation_ai_failed',
435 + $message,
436 + array(
437 + 'status' => 502,
438 + 'reason' => $reason,
439 + 'provider_status' => $provider_status,
440 + 'detail' => $detail,
441 + )
442 + );
379 443 }
380 444
381 445 /**
382 446 * Trim, tag-strip and cap a list of model-supplied strings.