From e91a95ac332f41511052a563cfbf0342aacf12a0 Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Thu, 16 Oct 2025 14:36:30 +0200 Subject: [PATCH 1/4] chore: draft embeddings API --- package-lock.json | 413 +++++++++++++++--------- package.json | 9 +- src/common/search/embeddingsProvider.ts | 82 +++++ 3 files changed, 345 insertions(+), 159 deletions(-) create mode 100644 src/common/search/embeddingsProvider.ts diff --git a/package-lock.json b/package-lock.json index 6b7ee0e98..367e30f5b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "oauth4webapi": "^3.8.0", "openapi-fetch": "^0.14.0", "ts-levenshtein": "^1.0.7", + "voyage-ai-provider": "^2.0.0", "yargs-parser": "21.1.1", "zod": "^3.25.76" }, @@ -33,9 +34,9 @@ "mongodb-mcp-server": "dist/esm/index.js" }, "devDependencies": { - "@ai-sdk/azure": "^1.3.24", - "@ai-sdk/google": "^1.2.22", - "@ai-sdk/openai": "^1.3.23", + "@ai-sdk/azure": "^2.0.53", + "@ai-sdk/google": "^2.0.23", + "@ai-sdk/openai": "^2.0.52", "@eslint/js": "^9.34.0", "@modelcontextprotocol/inspector": "^0.16.5", "@mongodb-js/oidc-mock-provider": "^0.11.3", @@ -48,7 +49,7 @@ "@typescript-eslint/parser": "^8.44.0", "@vitest/coverage-v8": "^3.2.4", "@vitest/eslint-plugin": "^1.3.4", - "ai": "^4.3.17", + "ai": "^5.0.72", "duplexpair": "^1.0.2", "eslint": "^9.34.0", "eslint-config-prettier": "^10.1.8", @@ -79,61 +80,76 @@ } }, "node_modules/@ai-sdk/azure": { - "version": "1.3.25", - "resolved": "https://registry.npmjs.org/@ai-sdk/azure/-/azure-1.3.25.tgz", - "integrity": "sha512-cTME89A9UYrza0t5pbY9b80yYY02Q5ALQdB2WP3R7/Yl1PLwbFChx994Q3Un0G2XV5h3arlm4fZTViY10isjhQ==", + "version": "2.0.53", + "resolved": "https://registry.npmjs.org/@ai-sdk/azure/-/azure-2.0.53.tgz", + "integrity": "sha512-RS8057AUOjPGw1tjEi/TnclPhxjVtAuaxk0Ta8obE9QDKWSbcg+xKq1L1P1ksRlQAliUCoZWe/jbH7wB+/PXTw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@ai-sdk/openai": "1.3.24", - "@ai-sdk/provider": "1.1.3", - "@ai-sdk/provider-utils": "2.2.8" + "@ai-sdk/openai": "2.0.52", + "@ai-sdk/provider": "2.0.0", + "@ai-sdk/provider-utils": "3.0.12" }, "engines": { "node": ">=18" }, "peerDependencies": { - "zod": "^3.0.0" + "zod": "^3.25.76 || ^4.1.8" } }, - "node_modules/@ai-sdk/google": { - "version": "1.2.22", - "resolved": "https://registry.npmjs.org/@ai-sdk/google/-/google-1.2.22.tgz", - "integrity": "sha512-Ppxu3DIieF1G9pyQ5O1Z646GYR0gkC57YdBqXJ82qvCdhEhZHu0TWhmnOoeIWe2olSbuDeoOY+MfJrW8dzS3Hw==", + "node_modules/@ai-sdk/azure/node_modules/@ai-sdk/provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-2.0.0.tgz", + "integrity": "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "1.1.3", - "@ai-sdk/provider-utils": "2.2.8" + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ai-sdk/azure/node_modules/@ai-sdk/provider-utils": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.12.tgz", + "integrity": "sha512-ZtbdvYxdMoria+2SlNarEk6Hlgyf+zzcznlD55EAl+7VZvJaSg2sqPvwArY7L6TfDEDJsnCq0fdhBSkYo0Xqdg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "2.0.0", + "@standard-schema/spec": "^1.0.0", + "eventsource-parser": "^3.0.5" }, "engines": { "node": ">=18" }, "peerDependencies": { - "zod": "^3.0.0" + "zod": "^3.25.76 || ^4.1.8" } }, - "node_modules/@ai-sdk/openai": { - "version": "1.3.24", - "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-1.3.24.tgz", - "integrity": "sha512-GYXnGJTHRTZc4gJMSmFRgEQudjqd4PUN0ZjQhPwOAYH1yOAvQoG/Ikqs+HyISRbLPCrhbZnPKCNHuRU4OfpW0Q==", + "node_modules/@ai-sdk/gateway": { + "version": "1.0.40", + "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-1.0.40.tgz", + "integrity": "sha512-zlixM9jac0w0jjYl5gwNq+w9nydvraAmLaZQbbh+QpHU+OPkTIZmyBcKeTq5eGQKQxhi+oquHxzCSKyJx3egGw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "1.1.3", - "@ai-sdk/provider-utils": "2.2.8" + "@ai-sdk/provider": "2.0.0", + "@ai-sdk/provider-utils": "3.0.12", + "@vercel/oidc": "3.0.2" }, "engines": { "node": ">=18" }, "peerDependencies": { - "zod": "^3.0.0" + "zod": "^3.25.76 || ^4.1.8" } }, - "node_modules/@ai-sdk/provider": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.1.3.tgz", - "integrity": "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==", + "node_modules/@ai-sdk/gateway/node_modules/@ai-sdk/provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-2.0.0.tgz", + "integrity": "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -143,59 +159,143 @@ "node": ">=18" } }, - "node_modules/@ai-sdk/provider-utils": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-2.2.8.tgz", - "integrity": "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==", + "node_modules/@ai-sdk/gateway/node_modules/@ai-sdk/provider-utils": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.12.tgz", + "integrity": "sha512-ZtbdvYxdMoria+2SlNarEk6Hlgyf+zzcznlD55EAl+7VZvJaSg2sqPvwArY7L6TfDEDJsnCq0fdhBSkYo0Xqdg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "1.1.3", - "nanoid": "^3.3.8", - "secure-json-parse": "^2.7.0" + "@ai-sdk/provider": "2.0.0", + "@standard-schema/spec": "^1.0.0", + "eventsource-parser": "^3.0.5" }, "engines": { "node": ">=18" }, "peerDependencies": { - "zod": "^3.23.8" + "zod": "^3.25.76 || ^4.1.8" } }, - "node_modules/@ai-sdk/react": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-1.2.12.tgz", - "integrity": "sha512-jK1IZZ22evPZoQW3vlkZ7wvjYGYF+tRBKXtrcolduIkQ/m/sOAVcVeVDUDvh1T91xCnWCdUGCPZg2avZ90mv3g==", + "node_modules/@ai-sdk/google": { + "version": "2.0.23", + "resolved": "https://registry.npmjs.org/@ai-sdk/google/-/google-2.0.23.tgz", + "integrity": "sha512-VbCnKR+6aWUVLkAiSW5gUEtST7KueEmlt+d6qwDikxlLnFG9pzy59je8MiDVeM5G2tuSXbvZQF78PGIfXDBmow==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider-utils": "2.2.8", - "@ai-sdk/ui-utils": "1.2.11", - "swr": "^2.2.5", - "throttleit": "2.1.0" + "@ai-sdk/provider": "2.0.0", + "@ai-sdk/provider-utils": "3.0.12" }, "engines": { "node": ">=18" }, "peerDependencies": { - "react": "^18 || ^19 || ^19.0.0-rc", - "zod": "^3.23.8" + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/google/node_modules/@ai-sdk/provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-2.0.0.tgz", + "integrity": "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" }, - "peerDependenciesMeta": { - "zod": { - "optional": true - } + "engines": { + "node": ">=18" + } + }, + "node_modules/@ai-sdk/google/node_modules/@ai-sdk/provider-utils": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.12.tgz", + "integrity": "sha512-ZtbdvYxdMoria+2SlNarEk6Hlgyf+zzcznlD55EAl+7VZvJaSg2sqPvwArY7L6TfDEDJsnCq0fdhBSkYo0Xqdg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "2.0.0", + "@standard-schema/spec": "^1.0.0", + "eventsource-parser": "^3.0.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/openai": { + "version": "2.0.52", + "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-2.0.52.tgz", + "integrity": "sha512-n1arAo4+63e6/FFE6z/1ZsZbiOl4cfsoZ3F4i2X7LPIEea786Y2yd7Qdr7AdB4HTLVo3OSb1PHVIcQmvYIhmEA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "2.0.0", + "@ai-sdk/provider-utils": "3.0.12" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/openai/node_modules/@ai-sdk/provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-2.0.0.tgz", + "integrity": "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ai-sdk/openai/node_modules/@ai-sdk/provider-utils": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.12.tgz", + "integrity": "sha512-ZtbdvYxdMoria+2SlNarEk6Hlgyf+zzcznlD55EAl+7VZvJaSg2sqPvwArY7L6TfDEDJsnCq0fdhBSkYo0Xqdg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "2.0.0", + "@standard-schema/spec": "^1.0.0", + "eventsource-parser": "^3.0.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/@ai-sdk/provider": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.1.3.tgz", + "integrity": "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" } }, - "node_modules/@ai-sdk/ui-utils": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@ai-sdk/ui-utils/-/ui-utils-1.2.11.tgz", - "integrity": "sha512-3zcwCc8ezzFlwp3ZD15wAPjf2Au4s3vAbKsXQVyhxODHcmu0iyPO2Eua6D/vicq/AUm/BAo60r97O6HU+EI0+w==", + "node_modules/@ai-sdk/provider-utils": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-2.2.8.tgz", + "integrity": "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==", "dev": true, "license": "Apache-2.0", "dependencies": { "@ai-sdk/provider": "1.1.3", - "@ai-sdk/provider-utils": "2.2.8", - "zod-to-json-schema": "^3.24.1" + "nanoid": "^3.3.8", + "secure-json-parse": "^2.7.0" }, "engines": { "node": ">=18" @@ -5277,6 +5377,12 @@ "node": ">=18.0.0" } }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "license": "MIT" + }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", @@ -5360,13 +5466,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/diff-match-patch": { - "version": "1.0.36", - "resolved": "https://registry.npmjs.org/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz", - "integrity": "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/docker-modem": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/@types/docker-modem/-/docker-modem-3.0.6.tgz", @@ -6024,6 +6123,16 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@vercel/oidc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.0.2.tgz", + "integrity": "sha512-JekxQ0RApo4gS4un/iMGsIL1/k4KUBe3HmnGcDvzHuFBdQdudEJgTqcsJC7y6Ul4Yw5CeykgvQbX2XeEJd0+DA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 20" + } + }, "node_modules/@vitest/coverage-v8": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.2.4.tgz", @@ -6269,30 +6378,53 @@ } }, "node_modules/ai": { - "version": "4.3.19", - "resolved": "https://registry.npmjs.org/ai/-/ai-4.3.19.tgz", - "integrity": "sha512-dIE2bfNpqHN3r6IINp9znguYdhIOheKW2LDigAMrgt/upT3B8eBGPSCblENvaZGoq+hxaN9fSMzjWpbqloP+7Q==", + "version": "5.0.72", + "resolved": "https://registry.npmjs.org/ai/-/ai-5.0.72.tgz", + "integrity": "sha512-LB4APrlESLGHG/5x+VVdl0yYPpHPHpnGd5Gwl7AWVL+n7T0GYsNos/S/6dZ5CZzxLnPPEBkRgvJC4rupeZqyNg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "1.1.3", - "@ai-sdk/provider-utils": "2.2.8", - "@ai-sdk/react": "1.2.12", - "@ai-sdk/ui-utils": "1.2.11", - "@opentelemetry/api": "1.9.0", - "jsondiffpatch": "0.6.0" + "@ai-sdk/gateway": "1.0.40", + "@ai-sdk/provider": "2.0.0", + "@ai-sdk/provider-utils": "3.0.12", + "@opentelemetry/api": "1.9.0" }, "engines": { "node": ">=18" }, "peerDependencies": { - "react": "^18 || ^19 || ^19.0.0-rc", - "zod": "^3.23.8" + "zod": "^3.25.76 || ^4.1.8" + } + }, + "node_modules/ai/node_modules/@ai-sdk/provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-2.0.0.tgz", + "integrity": "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" }, - "peerDependenciesMeta": { - "react": { - "optional": true - } + "engines": { + "node": ">=18" + } + }, + "node_modules/ai/node_modules/@ai-sdk/provider-utils": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.12.tgz", + "integrity": "sha512-ZtbdvYxdMoria+2SlNarEk6Hlgyf+zzcznlD55EAl+7VZvJaSg2sqPvwArY7L6TfDEDJsnCq0fdhBSkYo0Xqdg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "2.0.0", + "@standard-schema/spec": "^1.0.0", + "eventsource-parser": "^3.0.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" } }, "node_modules/ajv": { @@ -8098,16 +8230,6 @@ "node": ">= 0.8" } }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/detect-libc": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", @@ -8135,13 +8257,6 @@ "node": ">=0.3.1" } }, - "node_modules/diff-match-patch": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", - "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -10642,7 +10757,6 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true, "license": "(AFL-2.1 OR BSD-3-Clause)" }, "node_modules/json-schema-to-ts": { @@ -10674,37 +10788,6 @@ "dev": true, "license": "MIT" }, - "node_modules/jsondiffpatch": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/jsondiffpatch/-/jsondiffpatch-0.6.0.tgz", - "integrity": "sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/diff-match-patch": "^1.0.36", - "chalk": "^5.3.0", - "diff-match-patch": "^1.0.5" - }, - "bin": { - "jsondiffpatch": "bin/jsondiffpatch.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - } - }, - "node_modules/jsondiffpatch/node_modules/chalk": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.0.tgz", - "integrity": "sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/jsonpath-plus": { "version": "10.3.0", "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.3.0.tgz", @@ -14665,20 +14748,6 @@ "node": ">= 6" } }, - "node_modules/swr": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.6.tgz", - "integrity": "sha512-wfHRmHWk/isGNMwlLGlZX5Gzz/uTgo0o2IRuTMcf4CPuPFJZlq0rDaKUx+ozB5nBOReNV1kiOyzMfj+MBMikLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "dequal": "^2.0.3", - "use-sync-external-store": "^1.4.0" - }, - "peerDependencies": { - "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, "node_modules/synckit": { "version": "0.11.11", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", @@ -15095,19 +15164,6 @@ } } }, - "node_modules/throttleit": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-2.1.0.tgz", - "integrity": "sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -16021,6 +16077,53 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/voyage-ai-provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/voyage-ai-provider/-/voyage-ai-provider-2.0.0.tgz", + "integrity": "sha512-AX00egENhHOAfuHAhvmoBVQNG6+f717763CfyPefjahDTxbt6nCE0IlDXn5nkzLIu00JoM/PDFYDYQ17NYQqPw==", + "license": "MIT", + "dependencies": { + "@ai-sdk/provider": "^2.0.0", + "@ai-sdk/provider-utils": "^3.0.0" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/voyage-ai-provider/node_modules/@ai-sdk/provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-2.0.0.tgz", + "integrity": "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==", + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/voyage-ai-provider/node_modules/@ai-sdk/provider-utils": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.12.tgz", + "integrity": "sha512-ZtbdvYxdMoria+2SlNarEk6Hlgyf+zzcznlD55EAl+7VZvJaSg2sqPvwArY7L6TfDEDJsnCq0fdhBSkYo0Xqdg==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "2.0.0", + "@standard-schema/spec": "^1.0.0", + "eventsource-parser": "^3.0.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.25.76 || ^4.1.8" + } + }, "node_modules/walk-up-path": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-4.0.0.tgz", diff --git a/package.json b/package.json index 659d67283..7626afc75 100644 --- a/package.json +++ b/package.json @@ -60,9 +60,9 @@ }, "license": "Apache-2.0", "devDependencies": { - "@ai-sdk/azure": "^1.3.24", - "@ai-sdk/google": "^1.2.22", - "@ai-sdk/openai": "^1.3.23", + "@ai-sdk/azure": "^2.0.53", + "@ai-sdk/google": "^2.0.23", + "@ai-sdk/openai": "^2.0.52", "@eslint/js": "^9.34.0", "@modelcontextprotocol/inspector": "^0.16.5", "@mongodb-js/oidc-mock-provider": "^0.11.3", @@ -75,7 +75,7 @@ "@typescript-eslint/parser": "^8.44.0", "@vitest/coverage-v8": "^3.2.4", "@vitest/eslint-plugin": "^1.3.4", - "ai": "^4.3.17", + "ai": "^5.0.72", "duplexpair": "^1.0.2", "eslint": "^9.34.0", "eslint-config-prettier": "^10.1.8", @@ -116,6 +116,7 @@ "oauth4webapi": "^3.8.0", "openapi-fetch": "^0.14.0", "ts-levenshtein": "^1.0.7", + "voyage-ai-provider": "^2.0.0", "yargs-parser": "21.1.1", "zod": "^3.25.76" }, diff --git a/src/common/search/embeddingsProvider.ts b/src/common/search/embeddingsProvider.ts new file mode 100644 index 000000000..2c98b02b8 --- /dev/null +++ b/src/common/search/embeddingsProvider.ts @@ -0,0 +1,82 @@ +import { createVoyage } from "voyage-ai-provider"; +import type { VoyageProvider } from "voyage-ai-provider"; +import { embedMany } from "ai"; +import type { UserConfig } from "../config.js"; +import assert from "assert"; +import { createFetch } from "@mongodb-js/devtools-proxy-support"; +import { z } from "zod"; + +const zEmbeddingsInput = z.string(); +type EmbeddingsInput = z.infer; +type Embeddings = number[]; + +interface EmbeddingsProvider { + embed(modelId: SupportedModels, content: EmbeddingsInput[], parameters: unknown): Promise; +} + +const zVoyageSupportedDimensions = z + .union([z.literal(256), z.literal(512), z.literal(1024), z.literal(2048)]) + .default(1024); + +const zVoyageQuantization = z.enum(["float", "int8", "binary", "ubinary"]).default("float"); +const zVoyageInputQuery = z.enum(["query", "document"]); + +export const zVoyageModels = z.enum(["voyage-3-large", "voyage-3.5", "voyage-3.5-lite", "voyage-code-3"]); +export const zVoyageParameters = { + "voyage-3-large": z.object({ + inputType: zVoyageInputQuery, + outputDimensions: zVoyageSupportedDimensions, + outputDtype: zVoyageQuantization, + }), + "voyage-3.5": z.object({ + inputType: zVoyageInputQuery, + outputDimensions: zVoyageSupportedDimensions, + outputDtype: zVoyageQuantization, + }), + "voyage-3.5-lite": z.object({ + inputType: zVoyageInputQuery, + outputDimensions: zVoyageSupportedDimensions, + outputDtype: zVoyageQuantization, + }), + "voyage-code-3": z.object({ + inputType: zVoyageInputQuery, + outputDimensions: zVoyageSupportedDimensions, + outputDtype: zVoyageQuantization, + }), +} as const; + +type VoyageModels = z.infer; +class VoyageEmbeddingsProvider implements EmbeddingsProvider { + private readonly voyage: VoyageProvider; + + constructor(userConfig: UserConfig, providedFetch?: typeof fetch) { + assert(userConfig.voyageApiKey, "voyageApiKey does not exist. This is likely a bug."); + + const customFetch: typeof fetch = (providedFetch ?? + createFetch({ useEnvironmentVariableProxies: true })) as unknown as typeof fetch; + + this.voyage = createVoyage({ apiKey: userConfig.voyageApiKey, fetch: customFetch }); + } + + static isConfiguredIn(userConfig: UserConfig): boolean { + return !!userConfig.voyageApiKey; + } + + async embed( + modelId: Model, + content: EmbeddingsInput[], + parameters: z.infer<(typeof zVoyageParameters)[Model]> + ): Promise { + const model = this.voyage.textEmbeddingModel(modelId); + const { embeddings } = await embedMany({ model, values: content, providerOptions: { voyage: parameters } }); + return embeddings; + } +} + +export function getEmbeddingsProvider(userConfig: UserConfig): EmbeddingsProvider | undefined { + if (VoyageEmbeddingsProvider.isConfiguredIn(userConfig)) { + return new VoyageEmbeddingsProvider(userConfig); + } + + return undefined; +} From d54e5885b9a2ac03945899c1c5ccc7768e726975 Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Thu, 16 Oct 2025 16:16:24 +0200 Subject: [PATCH 2/4] chore: upgrade the vercel sdk, use new azure URL and remove ollama --- .github/workflows/accuracy-tests.yml | 2 +- package-lock.json | 69 ---------------------------- package.json | 1 - tests/accuracy/sdk/agent.ts | 16 +++---- tests/accuracy/sdk/models.ts | 29 +++--------- 5 files changed, 15 insertions(+), 102 deletions(-) diff --git a/.github/workflows/accuracy-tests.yml b/.github/workflows/accuracy-tests.yml index 0b31b7c97..753e0acf8 100644 --- a/.github/workflows/accuracy-tests.yml +++ b/.github/workflows/accuracy-tests.yml @@ -21,7 +21,7 @@ jobs: MDB_OPEN_AI_API_KEY: ${{ secrets.ACCURACY_OPEN_AI_API_KEY }} MDB_GEMINI_API_KEY: ${{ secrets.ACCURACY_GEMINI_API_KEY }} MDB_AZURE_OPEN_AI_API_KEY: ${{ secrets.ACCURACY_AZURE_OPEN_AI_API_KEY }} - MDB_AZURE_OPEN_AI_API_URL: ${{ vars.ACCURACY_AZURE_OPEN_AI_API_URL }} + MDB_AZURE_OPEN_AI_API_URL: ${{ vars.ACCURACY_AZURE_OPEN_AI_API_URL_V2 }} MDB_ACCURACY_MDB_URL: ${{ secrets.ACCURACY_MDB_CONNECTION_STRING }} MDB_ACCURACY_MDB_DB: ${{ vars.ACCURACY_MDB_DB }} MDB_ACCURACY_MDB_COLLECTION: ${{ vars.ACCURACY_MDB_COLLECTION }} diff --git a/package-lock.json b/package-lock.json index 367e30f5b..293092684 100644 --- a/package-lock.json +++ b/package-lock.json @@ -58,7 +58,6 @@ "knip": "^5.63.1", "mongodb": "^6.19.0", "mongodb-runner": "^5.9.2", - "ollama-ai-provider": "^1.2.0", "openapi-types": "^12.1.3", "openapi-typescript": "^7.9.1", "prettier": "^3.6.2", @@ -273,37 +272,6 @@ "zod": "^3.25.76 || ^4.1.8" } }, - "node_modules/@ai-sdk/provider": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.1.3.tgz", - "integrity": "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "json-schema": "^0.4.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@ai-sdk/provider-utils": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-2.2.8.tgz", - "integrity": "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@ai-sdk/provider": "1.1.3", - "nanoid": "^3.3.8", - "secure-json-parse": "^2.7.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.23.8" - } - }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -11987,29 +11955,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ollama-ai-provider": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ollama-ai-provider/-/ollama-ai-provider-1.2.0.tgz", - "integrity": "sha512-jTNFruwe3O/ruJeppI/quoOUxG7NA6blG3ZyQj3lei4+NnJo7bi3eIRWqlVpRlu/mbzbFXeJSBuYQWF6pzGKww==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@ai-sdk/provider": "^1.0.0", - "@ai-sdk/provider-utils": "^2.0.0", - "partial-json": "0.1.7" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.0.0" - }, - "peerDependenciesMeta": { - "zod": { - "optional": true - } - } - }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -12398,13 +12343,6 @@ "node": ">= 0.8" } }, - "node_modules/partial-json": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/partial-json/-/partial-json-0.1.7.tgz", - "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", - "dev": true, - "license": "MIT" - }, "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", @@ -13613,13 +13551,6 @@ "loose-envify": "^1.1.0" } }, - "node_modules/secure-json-parse": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", - "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", - "dev": true, - "license": "BSD-3-Clause" - }, "node_modules/seek-bzip": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz", diff --git a/package.json b/package.json index 7626afc75..eab40d55c 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,6 @@ "knip": "^5.63.1", "mongodb": "^6.19.0", "mongodb-runner": "^5.9.2", - "ollama-ai-provider": "^1.2.0", "openapi-types": "^12.1.3", "openapi-typescript": "^7.9.1", "prettier": "^3.6.2", diff --git a/tests/accuracy/sdk/agent.ts b/tests/accuracy/sdk/agent.ts index cf700fd9c..daf762352 100644 --- a/tests/accuracy/sdk/agent.ts +++ b/tests/accuracy/sdk/agent.ts @@ -1,5 +1,5 @@ -import type { LanguageModelV1, experimental_createMCPClient } from "ai"; -import { generateText } from "ai"; +import type { LanguageModel, experimental_createMCPClient } from "ai"; +import { stepCountIs, generateText } from "ai"; import type { Model } from "./models.js"; const systemPrompt = [ @@ -39,11 +39,11 @@ export interface Agent { export function getVercelToolCallingAgent( requestedSystemPrompt?: string -): Agent, VercelMCPClientTools, VercelAgentPromptResult> { +): Agent, VercelMCPClientTools, VercelAgentPromptResult> { return { async prompt( prompt: PromptDefinition, - model: Model, + model: Model, tools: VercelMCPClientTools ): Promise { let prompts: string[]; @@ -70,15 +70,15 @@ export function getVercelToolCallingAgent( system: [...systemPrompt, requestedSystemPrompt].filter(Boolean).join("\n"), prompt: p, tools, - maxSteps: 100, + stopWhen: stepCountIs(100), }); result.text += intermediateResult.text; result.messages.push(...intermediateResult.response.messages); result.respondingModel = intermediateResult.response.modelId; - result.tokensUsage.completionTokens += intermediateResult.usage.completionTokens; - result.tokensUsage.promptTokens += intermediateResult.usage.promptTokens; - result.tokensUsage.totalTokens += intermediateResult.usage.totalTokens; + result.tokensUsage.completionTokens += intermediateResult.usage.outputTokens ?? 0; + result.tokensUsage.promptTokens += intermediateResult.usage.inputTokens ?? 0; + result.tokensUsage.totalTokens += intermediateResult.usage.totalTokens ?? 0; } return result; diff --git a/tests/accuracy/sdk/models.ts b/tests/accuracy/sdk/models.ts index 05b542ce0..a1f4a9eca 100644 --- a/tests/accuracy/sdk/models.ts +++ b/tests/accuracy/sdk/models.ts @@ -1,10 +1,9 @@ -import type { LanguageModelV1 } from "ai"; +import type { LanguageModel } from "ai"; import { createGoogleGenerativeAI } from "@ai-sdk/google"; import { createAzure } from "@ai-sdk/azure"; import { createOpenAI } from "@ai-sdk/openai"; -import { ollama } from "ollama-ai-provider"; -export interface Model { +export interface Model { readonly modelName: string; readonly provider: string; readonly displayName: string; @@ -24,7 +23,7 @@ export class OpenAIModel implements Model { return !!process.env.MDB_OPEN_AI_API_KEY; } - getModel(): LanguageModelV1 { + getModel(): LanguageModel { return createOpenAI({ apiKey: process.env.MDB_OPEN_AI_API_KEY, })(this.modelName); @@ -43,10 +42,11 @@ export class AzureOpenAIModel implements Model { return !!process.env.MDB_AZURE_OPEN_AI_API_KEY && !!process.env.MDB_AZURE_OPEN_AI_API_URL; } - getModel(): LanguageModelV1 { + getModel(): LanguageModel { return createAzure({ baseURL: process.env.MDB_AZURE_OPEN_AI_API_URL, apiKey: process.env.MDB_AZURE_OPEN_AI_API_KEY, + useDeploymentBasedUrls: true, apiVersion: "2024-12-01-preview", })(this.modelName); } @@ -64,30 +64,13 @@ export class GeminiModel implements Model { return !!process.env.MDB_GEMINI_API_KEY; } - getModel(): LanguageModelV1 { + getModel(): LanguageModel { return createGoogleGenerativeAI({ apiKey: process.env.MDB_GEMINI_API_KEY, })(this.modelName); } } -export class OllamaModel implements Model { - readonly provider = "Ollama"; - readonly displayName: string; - - constructor(readonly modelName: string) { - this.displayName = `${this.provider} - ${modelName}`; - } - - isAvailable(): boolean { - return true; - } - - getModel(): LanguageModelV1 { - return ollama(this.modelName); - } -} - const ALL_TESTABLE_MODELS: Model[] = [new AzureOpenAIModel("gpt-4o")]; export function getAvailableModels(): Model[] { From 71d6a7b32485761f4888b0ddd909f029f82f11c9 Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Thu, 16 Oct 2025 16:38:52 +0200 Subject: [PATCH 3/4] chore: upgrade ai sdk and fix tests Also remove the embedding provider interface as it will be covered in another PR --- package-lock.json | 50 +------------ package.json | 1 - src/common/search/embeddingsProvider.ts | 82 --------------------- tests/accuracy/sdk/accuracyTestingClient.ts | 8 +- 4 files changed, 7 insertions(+), 134 deletions(-) delete mode 100644 src/common/search/embeddingsProvider.ts diff --git a/package-lock.json b/package-lock.json index 293092684..5e7cac5c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,6 @@ "oauth4webapi": "^3.8.0", "openapi-fetch": "^0.14.0", "ts-levenshtein": "^1.0.7", - "voyage-ai-provider": "^2.0.0", "yargs-parser": "21.1.1", "zod": "^3.25.76" }, @@ -5349,6 +5348,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "dev": true, "license": "MIT" }, "node_modules/@tootallnate/quickjs-emscripten": { @@ -10725,6 +10725,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true, "license": "(AFL-2.1 OR BSD-3-Clause)" }, "node_modules/json-schema-to-ts": { @@ -16008,53 +16009,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/voyage-ai-provider": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/voyage-ai-provider/-/voyage-ai-provider-2.0.0.tgz", - "integrity": "sha512-AX00egENhHOAfuHAhvmoBVQNG6+f717763CfyPefjahDTxbt6nCE0IlDXn5nkzLIu00JoM/PDFYDYQ17NYQqPw==", - "license": "MIT", - "dependencies": { - "@ai-sdk/provider": "^2.0.0", - "@ai-sdk/provider-utils": "^3.0.0" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4" - }, - "peerDependenciesMeta": { - "zod": { - "optional": true - } - } - }, - "node_modules/voyage-ai-provider/node_modules/@ai-sdk/provider": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-2.0.0.tgz", - "integrity": "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==", - "license": "Apache-2.0", - "dependencies": { - "json-schema": "^0.4.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/voyage-ai-provider/node_modules/@ai-sdk/provider-utils": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.12.tgz", - "integrity": "sha512-ZtbdvYxdMoria+2SlNarEk6Hlgyf+zzcznlD55EAl+7VZvJaSg2sqPvwArY7L6TfDEDJsnCq0fdhBSkYo0Xqdg==", - "license": "Apache-2.0", - "dependencies": { - "@ai-sdk/provider": "2.0.0", - "@standard-schema/spec": "^1.0.0", - "eventsource-parser": "^3.0.5" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, "node_modules/walk-up-path": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-4.0.0.tgz", diff --git a/package.json b/package.json index eab40d55c..a93ba9d7c 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,6 @@ "oauth4webapi": "^3.8.0", "openapi-fetch": "^0.14.0", "ts-levenshtein": "^1.0.7", - "voyage-ai-provider": "^2.0.0", "yargs-parser": "21.1.1", "zod": "^3.25.76" }, diff --git a/src/common/search/embeddingsProvider.ts b/src/common/search/embeddingsProvider.ts deleted file mode 100644 index 2c98b02b8..000000000 --- a/src/common/search/embeddingsProvider.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { createVoyage } from "voyage-ai-provider"; -import type { VoyageProvider } from "voyage-ai-provider"; -import { embedMany } from "ai"; -import type { UserConfig } from "../config.js"; -import assert from "assert"; -import { createFetch } from "@mongodb-js/devtools-proxy-support"; -import { z } from "zod"; - -const zEmbeddingsInput = z.string(); -type EmbeddingsInput = z.infer; -type Embeddings = number[]; - -interface EmbeddingsProvider { - embed(modelId: SupportedModels, content: EmbeddingsInput[], parameters: unknown): Promise; -} - -const zVoyageSupportedDimensions = z - .union([z.literal(256), z.literal(512), z.literal(1024), z.literal(2048)]) - .default(1024); - -const zVoyageQuantization = z.enum(["float", "int8", "binary", "ubinary"]).default("float"); -const zVoyageInputQuery = z.enum(["query", "document"]); - -export const zVoyageModels = z.enum(["voyage-3-large", "voyage-3.5", "voyage-3.5-lite", "voyage-code-3"]); -export const zVoyageParameters = { - "voyage-3-large": z.object({ - inputType: zVoyageInputQuery, - outputDimensions: zVoyageSupportedDimensions, - outputDtype: zVoyageQuantization, - }), - "voyage-3.5": z.object({ - inputType: zVoyageInputQuery, - outputDimensions: zVoyageSupportedDimensions, - outputDtype: zVoyageQuantization, - }), - "voyage-3.5-lite": z.object({ - inputType: zVoyageInputQuery, - outputDimensions: zVoyageSupportedDimensions, - outputDtype: zVoyageQuantization, - }), - "voyage-code-3": z.object({ - inputType: zVoyageInputQuery, - outputDimensions: zVoyageSupportedDimensions, - outputDtype: zVoyageQuantization, - }), -} as const; - -type VoyageModels = z.infer; -class VoyageEmbeddingsProvider implements EmbeddingsProvider { - private readonly voyage: VoyageProvider; - - constructor(userConfig: UserConfig, providedFetch?: typeof fetch) { - assert(userConfig.voyageApiKey, "voyageApiKey does not exist. This is likely a bug."); - - const customFetch: typeof fetch = (providedFetch ?? - createFetch({ useEnvironmentVariableProxies: true })) as unknown as typeof fetch; - - this.voyage = createVoyage({ apiKey: userConfig.voyageApiKey, fetch: customFetch }); - } - - static isConfiguredIn(userConfig: UserConfig): boolean { - return !!userConfig.voyageApiKey; - } - - async embed( - modelId: Model, - content: EmbeddingsInput[], - parameters: z.infer<(typeof zVoyageParameters)[Model]> - ): Promise { - const model = this.voyage.textEmbeddingModel(modelId); - const { embeddings } = await embedMany({ model, values: content, providerOptions: { voyage: parameters } }); - return embeddings; - } -} - -export function getEmbeddingsProvider(userConfig: UserConfig): EmbeddingsProvider | undefined { - if (VoyageEmbeddingsProvider.isConfiguredIn(userConfig)) { - return new VoyageEmbeddingsProvider(userConfig); - } - - return undefined; -} diff --git a/tests/accuracy/sdk/accuracyTestingClient.ts b/tests/accuracy/sdk/accuracyTestingClient.ts index 6ebed6878..8537bebdb 100644 --- a/tests/accuracy/sdk/accuracyTestingClient.ts +++ b/tests/accuracy/sdk/accuracyTestingClient.ts @@ -1,5 +1,6 @@ import { v4 as uuid } from "uuid"; import { experimental_createMCPClient as createMCPClient, tool as createVercelTool } from "ai"; +import type { ToolCallOptions } from "ai"; import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; @@ -36,7 +37,8 @@ export class AccuracyTestingClient { for (const [toolName, tool] of Object.entries(vercelTools)) { rewrappedVercelTools[toolName] = createVercelTool({ ...tool, - execute: async (args, options) => { + // eslint-disable-next-line + execute: (async (args: unknown, options: ToolCallOptions) => { this.llmToolCalls.push({ toolCallId: uuid(), toolName: toolName, @@ -60,8 +62,8 @@ export class AccuracyTestingClient { content: JSON.stringify(error), }; } - }, - }); + }) as any, // eslint-disable-line + }) as VercelMCPClientTools[string]; } return rewrappedVercelTools; From 0ac967ad65a34dffc7b7da82423953c162a2e0cc Mon Sep 17 00:00:00 2001 From: Kevin Mas Ruiz Date: Thu, 16 Oct 2025 17:22:35 +0200 Subject: [PATCH 4/4] chore: fix typings --- tests/accuracy/sdk/accuracyTestingClient.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/accuracy/sdk/accuracyTestingClient.ts b/tests/accuracy/sdk/accuracyTestingClient.ts index 8537bebdb..7d00d6ec7 100644 --- a/tests/accuracy/sdk/accuracyTestingClient.ts +++ b/tests/accuracy/sdk/accuracyTestingClient.ts @@ -1,6 +1,6 @@ import { v4 as uuid } from "uuid"; import { experimental_createMCPClient as createMCPClient, tool as createVercelTool } from "ai"; -import type { ToolCallOptions } from "ai"; +import type { Tool } from "ai"; import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; @@ -36,9 +36,10 @@ export class AccuracyTestingClient { const rewrappedVercelTools: VercelMCPClientTools = {}; for (const [toolName, tool] of Object.entries(vercelTools)) { rewrappedVercelTools[toolName] = createVercelTool({ - ...tool, - // eslint-disable-next-line - execute: (async (args: unknown, options: ToolCallOptions) => { + // tool is an insantiated tool, while createVercelTool requires a tool definition. + // by using this explicit casting, we ensure the type system understands what we are doing. + ...(tool as Tool), + execute: async (args, options) => { this.llmToolCalls.push({ toolCallId: uuid(), toolName: toolName, @@ -62,7 +63,7 @@ export class AccuracyTestingClient { content: JSON.stringify(error), }; } - }) as any, // eslint-disable-line + }, }) as VercelMCPClientTools[string]; }