Skip to content

feat: add Voyage AI provider support as embedding model#19

Open
ecairol wants to merge 1 commit into
mainfrom
feature/voyage-ai-provider
Open

feat: add Voyage AI provider support as embedding model#19
ecairol wants to merge 1 commit into
mainfrom
feature/voyage-ai-provider

Conversation

@ecairol
Copy link
Copy Markdown

@ecairol ecairol commented May 31, 2026

Also added several UX fixes for showing messages:

  • Remove silent errors by surfacing the error messages from the Provider
  • Fix "Save Settings" requiring two clicks when changing provider/model.
  • Bulk-generate modal now pre-selects and locks the Provider/Model to the active configuration

Summary

Adds Voyage AI as an embedding provider alongside OpenAI and Automattic, and fixes a set of embedding pipeline and Settings-UI issues surfaced while testing it.

Main change — Voyage AI provider

  • Register Voyage AI in the provider registry (api.voyageai.com, WPVDB_VOYAGE_API_KEY constant support, key encryption, settings UI).
  • Add Voyage models: voyage-4-lite, voyage-4-large, voyage-code-3, voyage-finance-2, voyage-law-2, with their selectable dimensions.
  • Support provider-specific dimension parameters: OpenAI-compatible APIs use dimensions, Voyage uses output_dimension (Models::get_dimension_param() / supports_dimensions()).
  • Introduce WPVDB_DEFAULT_EMBED_DIM (1024) as the requested embedding dimension.
  • Unit tests for the new model/provider metadata (tests/unit/ModelsTest.php).

NOTE: A second PR will be opened to make the dimension a selectable dropdown from the UI. But for the sake of this PR, it's still using the PHP const

Additional fixes (not Voyage-specific)

Error surfacing from third-parties, to avoid silent failures

  • Background embedding failures are captured and shown as a grouped, dismissible admin notice
  • Bulk-generate now reports per-post success/failure rather than always returning "success" for merely queuing.
  • API keys are validated on save: a newly entered key is verified with a lightweight request, and a rejection (401/403) shows an inline settings error as soon as an API key is added.

Settings UI

  • Fix "Save Settings" requiring two clicks when changing provider/model. The post-confirm resubmit used form.submit(), which is shadowed by submit_button()'s name="submit" control; now calls HTMLFormElement.prototype.submit.call(form).
  • Bulk-generate modal now pre-selects and locks the Provider/Model to the active configuration (the backend already uses the active provider), so the user can't select a choice that would be ignored by the backend.

Testing

  • Bulk-embedded posts with OpenAI (all persisted) and Voyage
  • Verified single-click save across provider changes; key-validation error on a bad key
  • Grouped failure notice rendering and clearing (eg: free tier of 3 embeds when no payment method is added)
  • IMPORTANT: if testing with an existing old DB, recreate the table so VECTOR(n) matches WPVDB_DEFAULT_EMBED_DIM (IMO it's better that we caught this caveat early and not when the project is being actively used)

…gs integration

Also added several UX fixes for showing messages:
 - Remove silent errors by surfacing the error messages from the Provider
 - Fix "Save Settings" requiring **two clicks** when changing provider/model.
 - Bulk-generate modal now **pre-selects and locks** the Provider/Model to the active configuration
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Voyage AI as a first-class embedding provider (alongside existing providers), plus several admin UX and embedding-pipeline improvements to better surface failures and reduce confusing configuration flows.

Changes:

  • Register Voyage AI provider + models, including provider-specific dimension parameter handling (output_dimension) and default embedding dimension support.
  • Improve error surfacing across the embedding pipeline (structured WP_Error codes, failure aggregation via admin notices).
  • Fix admin UX around settings saves and bulk embedding (single-click save, bulk embed modal locked to active provider/model, improved bulk embed response messaging).

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
wpvdb.php Introduces a default embedding dimension constant.
includes/class-wpvdb-providers.php Registers Voyage AI in the provider registry (base URL, API key constant, label/description).
includes/class-wpvdb-models.php Adds Voyage model metadata + dimension parameter support and compatibility helpers.
includes/class-wpvdb-core.php Maps provider HTTP status codes to structured embedding error codes; sends dimension under provider-specific parameter name.
includes/class-wpvdb-settings.php Adds Voyage defaults and API key constant support; validates/surfaces provider API key failures on save.
includes/class-wpvdb-queue.php Records embedding failures for later admin notice surfacing.
includes/class-wpvdb-admin.php Improves bulk embed reporting and adds grouped, dismissible admin notices for embedding failures.
admin/views/settings.php Adds Voyage settings UI (key, model, endpoint) and dimension-compatibility messaging.
admin/views/embeddings.php Locks bulk-embed provider/model to the active configuration to match backend behavior.
assets/js/admin.js Fixes settings “Save” submission by bypassing the submit name-shadowing issue.
tests/unit/ModelsTest.php Adds unit tests for Voyage provider models, dimension parameter name, and storage compatibility.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread wpvdb.php
Comment on lines +30 to 34
define( 'WPVDB_DEFAULT_EMBED_DIM', 1024 );

if ( ! defined( 'WPVDB_PLAYGROUND_SUPPORT_VERSION' ) ) {
define( 'WPVDB_PLAYGROUND_SUPPORT_VERSION', '1' );
}
Comment on lines +556 to +561
$failures[] = array(
'post_id' => (int) $post_id,
'provider' => (string) $provider,
'code' => $error->get_error_code(),
'message' => mb_substr( (string) $error->get_error_message(), 0, 200 ),
);
Comment on lines +1538 to +1559
if ( ! empty( $failed ) ) {
$recorded = get_transient( 'wpvdb_embedding_failures' );
$reason = '';
if ( is_array( $recorded ) && ! empty( $recorded ) ) {
$entry = end( $recorded );
$reason = isset( $entry['message'] ) ? (string) $entry['message'] : '';
}

$failed_message = sprintf(
/* translators: 1: number of posts that failed, 2: failure reason from the provider. */
_n( '%1$d post failed to embed: %2$s', '%1$d posts failed to embed: %2$s', count( $failed ), 'wpvdb' ),
count( $failed ),
$reason
);

wp_send_json_error(
array(
'message' => $failed_message,
'failed_ids' => $failed,
)
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants