Skip to content

Replace bundled ai-http-client with core wp-ai-client #1027

@chubes4

Description

@chubes4

Context

Data Machine currently bundles vendor/chubes4/ai-http-client (v2.0.13) — a filter-based AI provider abstraction layer. WordPress 7.0 core now ships wp-ai-client with equivalent functionality via a fluent OOP API (wp_ai_client_prompt()). The bundled library should be removed and all AI requests routed through core's client directly.

Key constraints:

  • Core's AI client does not support multisite (network-wide API key/model cascading). Data-machine must own that.
  • Core requires separate provider plugins (e.g., ai-provider-for-openai) to register actual provider implementations. Data-machine follows the same model.
  • No backwards compatibility layer — all chubes_ai_* filter hooks are eliminated; consuming code is rewritten.
  • No custom provider implementations — data-machine does not ship or register providers. That's a separate concern.
  • No adapter classRequestBuilder calls wp_ai_client_prompt() directly and normalizes the response inline.

API Comparison

Aspect ai-http-client (old) wp-ai-client (new)
Request Array via apply_filters('chubes_ai_request', ...) Fluent builder: wp_ai_client_prompt()->with_history()->using_model()->generate_text_result()
Response ['success'=>bool, 'data'=>['content','usage','tool_calls'], 'error'=>string] GenerativeAiResult|WP_Error with ->toText(), ->getTokenUsage(), candidates with MessagePart::getFunctionCall()
Tool calls in Array in $request['tools'] FunctionDeclaration objects via using_function_declarations()
Tool calls out $response['data']['tool_calls'] = [['name'=>..., 'parameters'=>...]] $candidate->getMessage()->getParts()$part->getFunctionCall()FunctionCall::getName(), ::getArgs(), ::getId()
API keys get_site_option('chubes_ai_http_shared_api_keys') (one array) Connectors system: individual get_option('connectors_ai_{id}_api_key') per provider
Multisite Built into key storage via get_site_option None — DM must own this
Streaming Supported (unused by DM) Not supported

Implementation Plan

Step 1: Create DataMachineAPIKeys — multisite key resolver

New file: inc/Engine/AI/DataMachineAPIKeys.php

Resolution order:

  1. Per-site: get_option('connectors_ai_{provider}_api_key')
  2. Network: NetworkSettings::get('api_keys')[$provider]
  3. Environment variable: {PROVIDER_ID}_API_KEY
  4. Empty string

Modify: inc/Core/NetworkSettings.php — add 'api_keys' to NETWORK_KEYS

Step 2: Rewrite RequestBuilder::build()

Modify: inc/Engine/AI/RequestBuilder.php

Replace lines 93-105 (apply_filters('chubes_ai_request', ...)) with direct wp_ai_client_prompt() calls inline:

  1. Resolve API key via DataMachineAPIKeys::get($provider)
  2. Set auth on registry: $registry->setProviderRequestAuthentication($provider, new ApiKeyRequestAuthentication($key))
  3. Extract system messages from $request['messages']using_system_instruction()
  4. Convert remaining messages to Message objects → with_history()
  5. Convert tools to FunctionDeclaration objects → using_function_declarations()
  6. Set provider/model → using_provider() + using_model(registry->getProviderModel())
  7. Apply config → using_temperature(), using_max_tokens() if set
  8. Call generate_text_result()
  9. Normalize GenerativeAiResult → DM's expected response array inline:
    • $result->toText()['data']['content']
    • $result->getTokenUsage()['data']['usage']
    • Tool calls from message parts → ['data']['tool_calls'] as [['name'=>..., 'parameters'=>...]]
    • WP_Error['success'=>false, 'error'=>...]

Step 3: Migrate API key storage

Modify: inc/Engine/Filters/DataMachineFilters.php

  • Remove the chubes_ai_provider_api_keys filter hook
  • Add one-time migration: read get_site_option('chubes_ai_http_shared_api_keys') → write each key into update_option('connectors_ai_{provider}_api_key', $key)

Step 4: Rewrite Providers::handle_get_providers()

Modify: inc/Api/Providers.php

Replace chubes_ai_providers, chubes_ai_provider_api_keys, chubes_ai_models filter calls with:

$registry = AiClient::defaultRegistry();
$provider_ids = $registry->getRegisteredProviderIds();
// For each: wp_get_connector($id) for metadata
// $registry->findProviderModelsMetadataForSupport() for models

Step 5: Rewrite API key management in SettingsAbilities

Modify: inc/Abilities/SettingsAbilities.php

  • getAiProviderSettings() (line 340): Replace apply_filters('chubes_ai_provider_api_keys', null) with reading from Connectors + NetworkSettings
  • executeUpdateSettings() (line 498-513): Write to update_option('connectors_ai_{provider}_api_key', ...) for per-site, NetworkSettings::update(['api_keys' => ...]) for network

Step 6: Update Chat.php provider validation

Modify: inc/Api/Chat/Chat.php (line 77) — replace apply_filters('chubes_ai_providers', array()) with AiClient::defaultRegistry()->getRegisteredProviderIds() or wp_get_connectors()

Step 7: Remove ai-http-client dependency

  • Remove from composer.json: "chubes4/ai-http-client": "^2.0.13"
  • Delete vendor/chubes4/ai-http-client/
  • Remove autoload references

Files to Modify

File Change
inc/Engine/AI/DataMachineAPIKeys.php NEW — multisite API key resolution
inc/Engine/AI/RequestBuilder.php Replace chubes_ai_request filter with direct wp_ai_client_prompt() calls
inc/Api/Providers.php Replace all chubes_ai_* filters with ProviderRegistry calls
inc/Abilities/SettingsAbilities.php Replace chubes_ai_provider_api_keys with Connectors + NetworkSettings
inc/Engine/Filters/DataMachineFilters.php Remove chubes_ai_provider_api_keys filter; add one-time key migration
inc/Api/Chat/Chat.php Replace chubes_ai_providers filter with registry check
inc/Core/NetworkSettings.php Add api_keys to NETWORK_KEYS
composer.json Remove chubes4/ai-http-client dependency
vendor/chubes4/ DELETE entire directory

What does NOT change

  • AIConversationLoop.php — consumes RequestBuilder::build() return value which keeps the same array shape
  • ConversationManager.php — builds DM's internal message format; RequestBuilder handles the translation
  • ToolExecutor.php, ToolPolicyResolver.php, ToolServiceProvider.php — tool execution unchanged
  • PromptBuilder.php (DM's directive system) — unchanged, still builds the $request array
  • All directive classes — unchanged
  • AIStep.php, ChatOrchestrator.php — unchanged (call AIConversationLoop which calls RequestBuilder)
  • Logger.php, DirectoryManager.php — unchanged multisite code

Key SDK Classes (for reference)

Class Full Namespace
Message WordPress\AiClient\Messages\DTO\Message
MessagePart WordPress\AiClient\Messages\DTO\MessagePart
MessageRoleEnum WordPress\AiClient\Messages\Enums\MessageRoleEnum
FunctionDeclaration WordPress\AiClient\Tools\DTO\FunctionDeclaration
FunctionCall WordPress\AiClient\Tools\DTO\FunctionCall
FunctionResponse WordPress\AiClient\Tools\DTO\FunctionResponse
AiClient WordPress\AiClient\AiClient
ProviderRegistry WordPress\AiClient\Providers\ProviderRegistry
GenerativeAiResult WordPress\AiClient\Results\DTO\GenerativeAiResult
ApiKeyRequestAuthentication WordPress\AiClient\Providers\Http\DTO\ApiKeyRequestAuthentication
WP_AI_Client_Prompt_Builder (WordPress wrapper class)

Verification Checklist

  • RequestBuilder::build() correctly translates DM arrays → wp-ai-client calls and normalizes response back
  • API key migration: chubes_ai_http_shared_api_keys → individual connectors_ai_* options
  • Multisite cascade: network-level key → per-site override → env var fallback
  • GET /datamachine/v1/providers returns correct data from registry
  • Chat flow end-to-end with tool calls
  • Pipeline flow with token tracking and handler completion
  • grep -r 'chubes_ai_' inc/ returns zero results

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions