diff --git a/CHANGELOG.md b/CHANGELOG.md index 237e1cd68..a9ef6ac54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ All notable changes to this project will be documented in this file, per [the Keep a Changelog standard](http://keepachangelog.com/), and will adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] - TBD +### Deprecated +- Deprecated the `AI_Service` class and the `get_ai_service()` helper introduced in 0.2.1. Neither is used anywhere in the plugin; experiments and abilities call `wp_ai_client_prompt()` directly. Both will be removed in the next major release ([#233](https://github.com/WordPress/ai/issues/233)). ## [1.2.0] - 2026-07-14 ### Added diff --git a/docs/ARCHITECTURE_OVERVIEW.md b/docs/ARCHITECTURE_OVERVIEW.md index 2077aaa38..4d9b86a4b 100644 --- a/docs/ARCHITECTURE_OVERVIEW.md +++ b/docs/ARCHITECTURE_OVERVIEW.md @@ -21,7 +21,7 @@ ai/ │ ├── Contracts/ # Interfaces (Feature contract) │ ├── Experiments/ # Experiment implementations (Abilities_Explorer, etc.) │ ├── Features/ # Feature registration and loading (Loader.php, Registry.php, Feature_Category.php) -│ ├── Services/ # External services (AI_Service) +│ ├── Services/ # Service classes (Guidelines; AI_Service, deprecated) │ ├── Settings/ # Plugin settings and admin pages │ ├── Asset_Loader.php # Asset loader utility class │ ├── Deprecated.php # Backward-compatibility layer for deprecated hooks/filters diff --git a/docs/experiments/multi-provider-support.md b/docs/experiments/multi-provider-support.md index e5f043cd4..e09eb105f 100644 --- a/docs/experiments/multi-provider-support.md +++ b/docs/experiments/multi-provider-support.md @@ -94,11 +94,3 @@ add_filter( 'wpai_has_ai_credentials', function( $has_credentials, $connectors ) - Multi-provider setups can improve resilience when individual providers are unavailable. - Keep model preference filters aligned with currently available provider model IDs. - If no provider supports the requested capability, abilities should return explicit `WP_Error` responses. - -## Related Files - -- `includes/helpers.php` -- `includes/Abstracts/Abstract_Ability.php` -- `includes/Services/AI_Service.php` -- `includes/Admin/Dashboard/AI_Status_Widget.php` -- `includes/Admin/Dashboard/AI_Capabilities_Widget.php` diff --git a/includes/Services/AI_Service.php b/includes/Services/AI_Service.php index b239535ae..930af654b 100644 --- a/includes/Services/AI_Service.php +++ b/includes/Services/AI_Service.php @@ -5,6 +5,8 @@ * Provides a centralized service layer for AI operations. * * @package WordPress\AI\Services + * + * @deprecated x.x.x This file will be removed in the next major release. */ declare( strict_types=1 ); @@ -21,7 +23,12 @@ * Manages AI provider configuration and provides a consistent interface * for features to communicate with AI providers. * + * Nothing in the plugin uses this class; features and abilities call + * `wp_ai_client_prompt()` directly. It is retained only so that any third-party + * code written against it keeps working for one release cycle. + * * @since 0.2.1 + * @deprecated x.x.x Use wp_ai_client_prompt() instead. */ class AI_Service { @@ -72,9 +79,14 @@ public static function get_instance(): self { /** * Private constructor to enforce singleton pattern. * + * The deprecation notice lives here rather than in `get_instance()` so that + * it is emitted once per request instead of on every call. + * * @since 0.2.1 */ - private function __construct() {} + private function __construct() { + _deprecated_class( self::class, 'x.x.x', 'wp_ai_client_prompt()' ); + } /** * Creates a text generation prompt builder with default configuration applied. diff --git a/includes/helpers.php b/includes/helpers.php index 37cb65068..483812dab 100644 --- a/includes/helpers.php +++ b/includes/helpers.php @@ -224,36 +224,27 @@ function get_preferred_models_for_text_generation(): array { /** * Gets the AI Service instance. * - * Provides a convenient way to access the AI Service for performing AI operations. + * Call `wp_ai_client_prompt()` directly instead. The prompt builder it returns + * exposes the full SDK API, so the only behavior this helper added was applying + * `get_preferred_models_for_text_generation()` by default: * - * Example usage: * ```php - * $service = WordPress\AI\get_ai_service(); + * $builder = wp_ai_client_prompt( 'Summarize this article...' ); * - * // Check if text generation is supported before generating - * $builder = $service->create_textgen_prompt( 'Summarize this article...' ); - * if ( ! $builder->is_supported_for_text_generation() ) { - * return new WP_Error( 'ai_unsupported', 'No AI provider supports text generation.' ); + * $models = WordPress\AI\get_preferred_models_for_text_generation(); + * if ( ! empty( $models ) ) { + * $builder = $builder->using_model_preference( ...$models ); * } - * $text = $builder->generate_text(); - * - * // With options array - * $text = $service->create_textgen_prompt( 'Translate to French: Hello', array( - * 'system_instruction' => 'You are a translator.', - * 'temperature' => 0.3, - * ) )->generate_text(); - * - * // Chain additional SDK methods - * $titles = $service->create_textgen_prompt( 'Generate titles for: My blog post' ) - * ->using_candidate_count( 5 ) - * ->generate_texts(); * ``` * * @since 0.2.1 + * @deprecated x.x.x Use wp_ai_client_prompt() instead. * * @return \WordPress\AI\Services\AI_Service The AI Service instance. */ function get_ai_service(): AI_Service { + _deprecated_function( __FUNCTION__, 'x.x.x', 'wp_ai_client_prompt()' ); + return AI_Service::get_instance(); } diff --git a/tests/Integration/Includes/Services/AI_ServiceTest.php b/tests/Integration/Includes/Services/AI_ServiceTest.php index 230122506..bf727fa56 100644 --- a/tests/Integration/Includes/Services/AI_ServiceTest.php +++ b/tests/Integration/Includes/Services/AI_ServiceTest.php @@ -1,12 +1,13 @@ service = AI_Service::get_instance(); + $this->reset_instance(); } /** @@ -42,15 +42,34 @@ public function setUp(): void { * @since 0.2.1 */ public function tearDown(): void { + $this->reset_instance(); parent::tearDown(); } + /** + * Resets the singleton instance. + * + * The `_deprecated_class()` notice fires from the constructor, which the + * singleton only reaches once per process. Clearing the instance around every + * test keeps that notice deterministic instead of landing on whichever test + * happens to run first. + * + * @since x.x.x + */ + private function reset_instance(): void { + $instance = new ReflectionProperty( AI_Service::class, 'instance' ); + $instance->setAccessible( true ); + $instance->setValue( null, null ); + } + /** * Test singleton instance. * * @since 0.2.1 */ public function test_get_instance_returns_singleton(): void { + $this->setExpectedDeprecated( AI_Service::class ); + $instance1 = AI_Service::get_instance(); $instance2 = AI_Service::get_instance(); @@ -63,10 +82,13 @@ public function test_get_instance_returns_singleton(): void { * @since 0.2.1 */ public function test_get_ai_service_helper_returns_instance(): void { + $this->setExpectedDeprecated( 'WordPress\AI\get_ai_service' ); + $this->setExpectedDeprecated( AI_Service::class ); + $service = get_ai_service(); $this->assertInstanceOf( AI_Service::class, $service, 'Helper should return AI_Service instance' ); - $this->assertSame( $this->service, $service, 'Helper should return singleton instance' ); + $this->assertSame( AI_Service::get_instance(), $service, 'Helper should return singleton instance' ); } /** @@ -75,7 +97,9 @@ public function test_get_ai_service_helper_returns_instance(): void { * @since 0.2.1 */ public function test_create_textgen_prompt_returns_builder(): void { - $builder = $this->service->create_textgen_prompt( 'Test prompt' ); + $this->setExpectedDeprecated( AI_Service::class ); + + $builder = AI_Service::get_instance()->create_textgen_prompt( 'Test prompt' ); $this->assertInstanceOf( \WP_AI_Client_Prompt_Builder::class, @@ -90,7 +114,9 @@ public function test_create_textgen_prompt_returns_builder(): void { * @since 0.2.1 */ public function test_create_textgen_prompt_with_options(): void { - $builder = $this->service->create_textgen_prompt( + $this->setExpectedDeprecated( AI_Service::class ); + + $builder = AI_Service::get_instance()->create_textgen_prompt( 'Test prompt', array( 'system_instruction' => 'You are helpful.', @@ -105,24 +131,4 @@ public function test_create_textgen_prompt_with_options(): void { 'Should return WP_AI_Client_Prompt_Builder instance with options applied' ); } - - /** - * Test ai_experiments_service_initialized action can be hooked. - * - * @since 0.2.1 - */ - public function test_init_action_is_hookable(): void { - $callback = static function () {}; - - add_action( 'ai_experiments_service_initialized', $callback ); - - // Verify callback was registered. - $this->assertNotFalse( - has_action( 'ai_experiments_service_initialized', $callback ), - 'Action should accept callbacks' - ); - - // Cleanup. - remove_action( 'ai_experiments_service_initialized', $callback ); - } }