From f6e5bc59ef3d3e93f663745f262d187d1a431b5d Mon Sep 17 00:00:00 2001 From: Mark Ritterman Date: Thu, 12 Feb 2026 10:49:38 +1100 Subject: [PATCH] feat(voyageai): add output_dimension support for embeddings Allow controlling the number of dimensions in Voyage AI embedding responses via the outputDimension provider option. This is useful for models like voyage-4 and voyage-multimodal-3.5 that support Matryoshka-style dimension truncation. Co-Authored-By: Claude Opus 4.6 --- src/Providers/VoyageAI/Embeddings.php | 1 + .../embeddings-with-output-dimension-1.json | 1 + tests/Providers/VoyageAI/EmbeddingsTest.php | 35 +++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 tests/Fixtures/voyageai/embeddings-with-output-dimension-1.json diff --git a/src/Providers/VoyageAI/Embeddings.php b/src/Providers/VoyageAI/Embeddings.php index 1cfc6065a..b8e4b10bd 100644 --- a/src/Providers/VoyageAI/Embeddings.php +++ b/src/Providers/VoyageAI/Embeddings.php @@ -51,6 +51,7 @@ protected function sendRequest(): void 'model' => $this->request->model(), 'input' => $this->request->inputs(), 'input_type' => $providerOptions['inputType'] ?? null, + 'output_dimension' => $providerOptions['outputDimension'] ?? null, 'truncation' => $providerOptions['truncation'] ?? null, ])); diff --git a/tests/Fixtures/voyageai/embeddings-with-output-dimension-1.json b/tests/Fixtures/voyageai/embeddings-with-output-dimension-1.json new file mode 100644 index 000000000..8490bab80 --- /dev/null +++ b/tests/Fixtures/voyageai/embeddings-with-output-dimension-1.json @@ -0,0 +1 @@ +{"object":"list","data":[{"object":"embedding","embedding":[0.1,0.2,0.3,0.4],"index":0}],"model":"voyage-3-lite","usage":{"total_tokens":8}} diff --git a/tests/Providers/VoyageAI/EmbeddingsTest.php b/tests/Providers/VoyageAI/EmbeddingsTest.php index e11bef069..61552693d 100644 --- a/tests/Providers/VoyageAI/EmbeddingsTest.php +++ b/tests/Providers/VoyageAI/EmbeddingsTest.php @@ -98,6 +98,41 @@ expect($response->usage->tokens)->toBe(7); }); +it('returns embeddings with outputDimension set', function (): void { + FixtureResponse::fakeResponseSequence('*', 'voyageai/embeddings-with-output-dimension'); + + $response = Prism::embeddings() + ->using(Provider::VoyageAI, 'voyage-3-lite') + ->fromInput('The food was delicious and the waiter...') + ->withProviderOptions(['outputDimension' => 4]) + ->asEmbeddings(); + + expect($response->embeddings)->toBeArray(); + expect($response->embeddings[0]->embedding)->toHaveCount(4); + expect($response->usage->tokens)->toBe(8); + + Http::assertSent(function ($request): bool { + $body = json_decode((string) $request->body(), true); + + return $body['output_dimension'] === 4; + }); +}); + +it('does not include output_dimension when not set', function (): void { + FixtureResponse::fakeResponseSequence('*', 'voyageai/embeddings-from-input'); + + Prism::embeddings() + ->using(Provider::VoyageAI, 'voyage-3-lite') + ->fromInput('The food was delicious and the waiter...') + ->asEmbeddings(); + + Http::assertSent(function ($request): bool { + $body = json_decode((string) $request->body(), true); + + return ! array_key_exists('output_dimension', $body); + }); +}); + it('throws a PrismRateLimitedException for a 429 response code', function (): void { Http::fake([ '*' => Http::response(