@tanstack/ai-vertex 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Tanner Linsley
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # @tanstack/ai-vertex
2
+
3
+ Google Vertex AI adapter for [TanStack AI](https://tanstack.com/ai).
4
+
5
+ Use this package to run Gemini models on Vertex. That gives you regional
6
+ endpoints and Google Cloud credentials (ADC, service accounts, or Vertex
7
+ express API keys).
8
+
9
+ Claude on Vertex lives in [`@tanstack/ai-anthropic/vertex`](https://tanstack.com/ai/latest/docs/adapters/anthropic).
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ pnpm add @tanstack/ai @tanstack/ai-vertex
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```ts
20
+ import { chat } from '@tanstack/ai'
21
+ import { vertexText } from '@tanstack/ai-vertex'
22
+
23
+ const stream = chat({
24
+ adapter: vertexText('gemini-3.7-flash', {
25
+ project: 'my-project',
26
+ location: 'europe-west1',
27
+ }),
28
+ messages: [{ role: 'user', content: 'Hello' }],
29
+ })
30
+ ```
31
+
32
+ See the [Vertex adapter docs](https://tanstack.com/ai/latest/docs/adapters/vertex).
@@ -0,0 +1,12 @@
1
+ import { GeminiClientConfig } from '@tanstack/ai-gemini';
2
+ export type VertexClientConfig = Omit<GeminiClientConfig, 'vertexai' | 'enterprise'>;
3
+ export type VertexVideoConfig = VertexClientConfig & {
4
+ allowUrlFetch?: boolean;
5
+ };
6
+ /**
7
+ * Resolves Vertex Gemini client options.
8
+ *
9
+ * Factory fields win. Then env. Then ADC inside `@google/genai`.
10
+ * Does not read `GEMINI_API_KEY` or `GOOGLE_API_KEY`.
11
+ */
12
+ export declare function resolveVertexGeminiOptions(config?: VertexClientConfig): GeminiClientConfig;
@@ -0,0 +1,33 @@
1
+ import { VertexAuthError } from "./errors.js";
2
+ //#region src/auth.ts
3
+ function nonEmpty(value) {
4
+ if (value === void 0 || value.length === 0) return;
5
+ return value;
6
+ }
7
+ function readEnv(name) {
8
+ if (typeof process === "undefined" || process.env === void 0) return;
9
+ return nonEmpty(process.env[name]);
10
+ }
11
+ /**
12
+ * Resolves Vertex Gemini client options.
13
+ *
14
+ * Factory fields win. Then env. Then ADC inside `@google/genai`.
15
+ * Does not read `GEMINI_API_KEY` or `GOOGLE_API_KEY`.
16
+ */
17
+ function resolveVertexGeminiOptions(config = {}) {
18
+ const project = nonEmpty(config.project) ?? readEnv("GOOGLE_CLOUD_PROJECT") ?? readEnv("GOOGLE_VERTEX_PROJECT");
19
+ const location = nonEmpty(config.location) ?? readEnv("GOOGLE_CLOUD_LOCATION") ?? readEnv("GOOGLE_VERTEX_LOCATION");
20
+ const apiKey = nonEmpty(config.apiKey) ?? readEnv("GOOGLE_VERTEX_API_KEY");
21
+ if (apiKey === void 0 && (project === void 0 || location === void 0)) throw new VertexAuthError("Vertex Gemini needs project and location, or an express apiKey. Pass project and location on the factory, or set GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION. For express mode, pass apiKey or set GOOGLE_VERTEX_API_KEY.");
22
+ return {
23
+ ...config,
24
+ vertexai: true,
25
+ ...project === void 0 ? {} : { project },
26
+ ...location === void 0 ? {} : { location },
27
+ ...apiKey === void 0 ? {} : { apiKey }
28
+ };
29
+ }
30
+ //#endregion
31
+ export { resolveVertexGeminiOptions };
32
+
33
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","names":[],"sources":["../../src/auth.ts"],"sourcesContent":["import { VertexAuthError } from './errors'\nimport type { GeminiClientConfig } from '@tanstack/ai-gemini'\n\nexport type VertexClientConfig = Omit<\n GeminiClientConfig,\n 'vertexai' | 'enterprise'\n>\n\nexport type VertexVideoConfig = VertexClientConfig & {\n allowUrlFetch?: boolean\n}\n\nfunction nonEmpty(value: string | undefined): string | undefined {\n if (value === undefined || value.length === 0) {\n return undefined\n }\n return value\n}\n\nfunction readEnv(name: string): string | undefined {\n if (typeof process === 'undefined' || process.env === undefined) {\n return undefined\n }\n return nonEmpty(process.env[name])\n}\n\n/**\n * Resolves Vertex Gemini client options.\n *\n * Factory fields win. Then env. Then ADC inside `@google/genai`.\n * Does not read `GEMINI_API_KEY` or `GOOGLE_API_KEY`.\n */\nexport function resolveVertexGeminiOptions(\n config: VertexClientConfig = {},\n): GeminiClientConfig {\n const project =\n nonEmpty(config.project) ??\n readEnv('GOOGLE_CLOUD_PROJECT') ??\n readEnv('GOOGLE_VERTEX_PROJECT')\n const location =\n nonEmpty(config.location) ??\n readEnv('GOOGLE_CLOUD_LOCATION') ??\n readEnv('GOOGLE_VERTEX_LOCATION')\n const apiKey = nonEmpty(config.apiKey) ?? readEnv('GOOGLE_VERTEX_API_KEY')\n\n if (\n apiKey === undefined &&\n (project === undefined || location === undefined)\n ) {\n throw new VertexAuthError(\n 'Vertex Gemini needs project and location, or an express apiKey. Pass project and location on the factory, or set GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION. For express mode, pass apiKey or set GOOGLE_VERTEX_API_KEY.',\n )\n }\n\n return {\n ...config,\n vertexai: true,\n ...(project === undefined ? {} : { project }),\n ...(location === undefined ? {} : { location }),\n ...(apiKey === undefined ? {} : { apiKey }),\n }\n}\n"],"mappings":";;AAYA,SAAS,SAAS,OAA+C;CAC/D,IAAI,UAAU,KAAA,KAAa,MAAM,WAAW,GAC1C;CAEF,OAAO;AACT;AAEA,SAAS,QAAQ,MAAkC;CACjD,IAAI,OAAO,YAAY,eAAe,QAAQ,QAAQ,KAAA,GACpD;CAEF,OAAO,SAAS,QAAQ,IAAI,KAAK;AACnC;;;;;;;AAQA,SAAgB,2BACd,SAA6B,CAAC,GACV;CACpB,MAAM,UACJ,SAAS,OAAO,OAAO,KACvB,QAAQ,sBAAsB,KAC9B,QAAQ,uBAAuB;CACjC,MAAM,WACJ,SAAS,OAAO,QAAQ,KACxB,QAAQ,uBAAuB,KAC/B,QAAQ,wBAAwB;CAClC,MAAM,SAAS,SAAS,OAAO,MAAM,KAAK,QAAQ,uBAAuB;CAEzE,IACE,WAAW,KAAA,MACV,YAAY,KAAA,KAAa,aAAa,KAAA,IAEvC,MAAM,IAAI,gBACR,8NACF;CAGF,OAAO;EACL,GAAG;EACH,UAAU;EACV,GAAI,YAAY,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ;EAC3C,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS;EAC7C,GAAI,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,OAAO;CAC3C;AACF"}
@@ -0,0 +1,3 @@
1
+ export declare class VertexAuthError extends Error {
2
+ constructor(message: string);
3
+ }
@@ -0,0 +1,11 @@
1
+ //#region src/errors.ts
2
+ var VertexAuthError = class extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "VertexAuthError";
6
+ }
7
+ };
8
+ //#endregion
9
+ export { VertexAuthError };
10
+
11
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","names":[],"sources":["../../src/errors.ts"],"sourcesContent":["export class VertexAuthError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'VertexAuthError'\n }\n}\n"],"mappings":";AAAA,IAAa,kBAAb,cAAqC,MAAM;CACzC,YAAY,SAAiB;EAC3B,MAAM,OAAO;EACb,KAAK,OAAO;CACd;AACF"}
@@ -0,0 +1,13 @@
1
+ import { ChatStreamSummarizeAdapter } from '@tanstack/ai/adapters';
2
+ import { GeminiAudioAdapter, GeminiEmbeddingAdapter, GeminiImageAdapter, GeminiTTSAdapter, GeminiTextAdapter, GeminiVideoAdapter, GeminiAudioModel, GeminiEmbeddingModel, GeminiImageModel, GeminiTTSModels, GeminiTextModel, GeminiVideoModel } from '@tanstack/ai-gemini';
3
+ import { VertexClientConfig, VertexVideoConfig } from './auth.js';
4
+ export { VertexAuthError } from './errors.js';
5
+ export { resolveVertexGeminiOptions, type VertexClientConfig, type VertexVideoConfig, } from './auth.js';
6
+ type GeminiTTSModel = (typeof GeminiTTSModels)[number];
7
+ export declare function vertexText<TModel extends GeminiTextModel>(model: TModel, config?: VertexClientConfig): GeminiTextAdapter<TModel>;
8
+ export declare function vertexSummarize<TModel extends GeminiTextModel>(model: TModel, config?: VertexClientConfig): ChatStreamSummarizeAdapter<TModel>;
9
+ export declare function vertexImage<TModel extends GeminiImageModel>(model: TModel, config?: VertexClientConfig): GeminiImageAdapter<TModel>;
10
+ export declare function vertexEmbedding<TModel extends GeminiEmbeddingModel>(model: TModel, config?: VertexClientConfig): GeminiEmbeddingAdapter<TModel>;
11
+ export declare function vertexSpeech<TModel extends GeminiTTSModel>(model: TModel, config?: VertexClientConfig): GeminiTTSAdapter<TModel>;
12
+ export declare function vertexAudio<TModel extends GeminiAudioModel>(model: TModel, config?: VertexClientConfig): GeminiAudioAdapter<TModel>;
13
+ export declare function vertexVideo<TModel extends GeminiVideoModel>(model: TModel, config?: VertexVideoConfig): GeminiVideoAdapter<TModel>;
@@ -0,0 +1,60 @@
1
+ import { VertexAuthError } from "./errors.js";
2
+ import { resolveVertexGeminiOptions } from "./auth.js";
3
+ import { ChatStreamSummarizeAdapter } from "@tanstack/ai/adapters";
4
+ import { GeminiAudioAdapter, GeminiEmbeddingAdapter, GeminiImageAdapter, GeminiTTSAdapter, GeminiTextAdapter, GeminiVideoAdapter } from "@tanstack/ai-gemini";
5
+ //#region src/index.ts
6
+ function createVertex(config = {}) {
7
+ const resolved = resolveVertexGeminiOptions(config);
8
+ return {
9
+ text(model) {
10
+ return new GeminiTextAdapter(resolved, model);
11
+ },
12
+ summarize(model) {
13
+ return new ChatStreamSummarizeAdapter(new GeminiTextAdapter(resolved, model), model, "gemini");
14
+ },
15
+ image(model) {
16
+ return new GeminiImageAdapter(resolved, model);
17
+ },
18
+ embedding(model) {
19
+ return new GeminiEmbeddingAdapter(resolved, model);
20
+ },
21
+ speech(model) {
22
+ return new GeminiTTSAdapter(resolved, model);
23
+ },
24
+ audio(model) {
25
+ return new GeminiAudioAdapter(resolved, model);
26
+ },
27
+ video(model, videoConfig) {
28
+ return new GeminiVideoAdapter({
29
+ ...resolved,
30
+ allowUrlFetch: videoConfig?.allowUrlFetch
31
+ }, model);
32
+ }
33
+ };
34
+ }
35
+ function vertexText(model, config = {}) {
36
+ return createVertex(config).text(model);
37
+ }
38
+ function vertexSummarize(model, config = {}) {
39
+ return createVertex(config).summarize(model);
40
+ }
41
+ function vertexImage(model, config = {}) {
42
+ return createVertex(config).image(model);
43
+ }
44
+ function vertexEmbedding(model, config = {}) {
45
+ return createVertex(config).embedding(model);
46
+ }
47
+ function vertexSpeech(model, config = {}) {
48
+ return createVertex(config).speech(model);
49
+ }
50
+ function vertexAudio(model, config = {}) {
51
+ return createVertex(config).audio(model);
52
+ }
53
+ function vertexVideo(model, config = {}) {
54
+ const { allowUrlFetch, ...client } = config;
55
+ return createVertex(client).video(model, { allowUrlFetch });
56
+ }
57
+ //#endregion
58
+ export { VertexAuthError, resolveVertexGeminiOptions, vertexAudio, vertexEmbedding, vertexImage, vertexSpeech, vertexSummarize, vertexText, vertexVideo };
59
+
60
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/index.ts"],"sourcesContent":["import { ChatStreamSummarizeAdapter } from '@tanstack/ai/adapters'\nimport {\n GeminiAudioAdapter,\n GeminiEmbeddingAdapter,\n GeminiImageAdapter,\n GeminiTTSAdapter,\n GeminiTextAdapter,\n GeminiVideoAdapter,\n} from '@tanstack/ai-gemini'\nimport { resolveVertexGeminiOptions } from './auth'\nimport type {\n GeminiAudioModel,\n GeminiEmbeddingModel,\n GeminiImageModel,\n GeminiTTSModels,\n GeminiTextModel,\n GeminiVideoModel,\n} from '@tanstack/ai-gemini'\nimport type { VertexClientConfig, VertexVideoConfig } from './auth'\n\nexport { VertexAuthError } from './errors'\nexport {\n resolveVertexGeminiOptions,\n type VertexClientConfig,\n type VertexVideoConfig,\n} from './auth'\n\ntype GeminiTTSModel = (typeof GeminiTTSModels)[number]\n\nfunction createVertex(config: VertexClientConfig = {}) {\n const resolved = resolveVertexGeminiOptions(config)\n return {\n text<TModel extends GeminiTextModel>(model: TModel) {\n return new GeminiTextAdapter(resolved, model)\n },\n summarize<TModel extends GeminiTextModel>(model: TModel) {\n return new ChatStreamSummarizeAdapter(\n new GeminiTextAdapter(resolved, model),\n model,\n 'gemini',\n )\n },\n image<TModel extends GeminiImageModel>(model: TModel) {\n return new GeminiImageAdapter(resolved, model)\n },\n embedding<TModel extends GeminiEmbeddingModel>(model: TModel) {\n return new GeminiEmbeddingAdapter(resolved, model)\n },\n speech<TModel extends GeminiTTSModel>(model: TModel) {\n return new GeminiTTSAdapter(resolved, model)\n },\n audio<TModel extends GeminiAudioModel>(model: TModel) {\n return new GeminiAudioAdapter(resolved, model)\n },\n video<TModel extends GeminiVideoModel>(\n model: TModel,\n videoConfig?: Pick<VertexVideoConfig, 'allowUrlFetch'>,\n ) {\n return new GeminiVideoAdapter(\n { ...resolved, allowUrlFetch: videoConfig?.allowUrlFetch },\n model,\n )\n },\n }\n}\n\nexport function vertexText<TModel extends GeminiTextModel>(\n model: TModel,\n config: VertexClientConfig = {},\n): GeminiTextAdapter<TModel> {\n return createVertex(config).text(model)\n}\n\nexport function vertexSummarize<TModel extends GeminiTextModel>(\n model: TModel,\n config: VertexClientConfig = {},\n): ChatStreamSummarizeAdapter<TModel> {\n return createVertex(config).summarize(model)\n}\n\nexport function vertexImage<TModel extends GeminiImageModel>(\n model: TModel,\n config: VertexClientConfig = {},\n): GeminiImageAdapter<TModel> {\n return createVertex(config).image(model)\n}\n\nexport function vertexEmbedding<TModel extends GeminiEmbeddingModel>(\n model: TModel,\n config: VertexClientConfig = {},\n): GeminiEmbeddingAdapter<TModel> {\n return createVertex(config).embedding(model)\n}\n\nexport function vertexSpeech<TModel extends GeminiTTSModel>(\n model: TModel,\n config: VertexClientConfig = {},\n): GeminiTTSAdapter<TModel> {\n return createVertex(config).speech(model)\n}\n\nexport function vertexAudio<TModel extends GeminiAudioModel>(\n model: TModel,\n config: VertexClientConfig = {},\n): GeminiAudioAdapter<TModel> {\n return createVertex(config).audio(model)\n}\n\nexport function vertexVideo<TModel extends GeminiVideoModel>(\n model: TModel,\n config: VertexVideoConfig = {},\n): GeminiVideoAdapter<TModel> {\n const { allowUrlFetch, ...client } = config\n return createVertex(client).video(model, { allowUrlFetch })\n}\n"],"mappings":";;;;;AA6BA,SAAS,aAAa,SAA6B,CAAC,GAAG;CACrD,MAAM,WAAW,2BAA2B,MAAM;CAClD,OAAO;EACL,KAAqC,OAAe;GAClD,OAAO,IAAI,kBAAkB,UAAU,KAAK;EAC9C;EACA,UAA0C,OAAe;GACvD,OAAO,IAAI,2BACT,IAAI,kBAAkB,UAAU,KAAK,GACrC,OACA,QACF;EACF;EACA,MAAuC,OAAe;GACpD,OAAO,IAAI,mBAAmB,UAAU,KAAK;EAC/C;EACA,UAA+C,OAAe;GAC5D,OAAO,IAAI,uBAAuB,UAAU,KAAK;EACnD;EACA,OAAsC,OAAe;GACnD,OAAO,IAAI,iBAAiB,UAAU,KAAK;EAC7C;EACA,MAAuC,OAAe;GACpD,OAAO,IAAI,mBAAmB,UAAU,KAAK;EAC/C;EACA,MACE,OACA,aACA;GACA,OAAO,IAAI,mBACT;IAAE,GAAG;IAAU,eAAe,aAAa;GAAc,GACzD,KACF;EACF;CACF;AACF;AAEA,SAAgB,WACd,OACA,SAA6B,CAAC,GACH;CAC3B,OAAO,aAAa,MAAM,CAAC,CAAC,KAAK,KAAK;AACxC;AAEA,SAAgB,gBACd,OACA,SAA6B,CAAC,GACM;CACpC,OAAO,aAAa,MAAM,CAAC,CAAC,UAAU,KAAK;AAC7C;AAEA,SAAgB,YACd,OACA,SAA6B,CAAC,GACF;CAC5B,OAAO,aAAa,MAAM,CAAC,CAAC,MAAM,KAAK;AACzC;AAEA,SAAgB,gBACd,OACA,SAA6B,CAAC,GACE;CAChC,OAAO,aAAa,MAAM,CAAC,CAAC,UAAU,KAAK;AAC7C;AAEA,SAAgB,aACd,OACA,SAA6B,CAAC,GACJ;CAC1B,OAAO,aAAa,MAAM,CAAC,CAAC,OAAO,KAAK;AAC1C;AAEA,SAAgB,YACd,OACA,SAA6B,CAAC,GACF;CAC5B,OAAO,aAAa,MAAM,CAAC,CAAC,MAAM,KAAK;AACzC;AAEA,SAAgB,YACd,OACA,SAA4B,CAAC,GACD;CAC5B,MAAM,EAAE,eAAe,GAAG,WAAW;CACrC,OAAO,aAAa,MAAM,CAAC,CAAC,MAAM,OAAO,EAAE,cAAc,CAAC;AAC5D"}
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@tanstack/ai-vertex",
3
+ "version": "0.1.0",
4
+ "description": "Google Vertex AI adapter for TanStack AI. Runs Gemini models on Vertex with regional endpoints and Google Cloud credentials.",
5
+ "author": "Tanner Linsley",
6
+ "license": "MIT",
7
+ "homepage": "https://tanstack.com/ai",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/TanStack/ai.git",
11
+ "directory": "packages/ai-vertex"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/TanStack/ai/issues"
15
+ },
16
+ "funding": {
17
+ "type": "github",
18
+ "url": "https://github.com/sponsors/tannerlinsley"
19
+ },
20
+ "type": "module",
21
+ "module": "./dist/esm/index.js",
22
+ "types": "./dist/esm/index.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/esm/index.d.ts",
26
+ "import": "./dist/esm/index.js"
27
+ }
28
+ },
29
+ "files": [
30
+ "dist",
31
+ "src"
32
+ ],
33
+ "keywords": [
34
+ "ai",
35
+ "ai-sdk",
36
+ "typescript",
37
+ "tanstack",
38
+ "vertex",
39
+ "vertex-ai",
40
+ "gemini",
41
+ "google",
42
+ "adapter"
43
+ ],
44
+ "dependencies": {
45
+ "@tanstack/ai-gemini": "^0.24.2"
46
+ },
47
+ "peerDependencies": {
48
+ "@tanstack/ai": "^0.47.2"
49
+ },
50
+ "devDependencies": {
51
+ "@google/genai": "^2.10.0",
52
+ "@vitest/coverage-v8": "4.1.10",
53
+ "vite": "^8.2.1",
54
+ "@tanstack/ai": "0.47.2"
55
+ },
56
+ "scripts": {
57
+ "build": "vite build",
58
+ "clean": "premove ./build ./dist",
59
+ "lint:fix": "oxlint src --type-aware --fix",
60
+ "test:build": "publint --strict",
61
+ "test:oxlint": "oxlint src --type-aware",
62
+ "test:lib": "vitest run",
63
+ "test:lib:dev": "pnpm test:lib --watch",
64
+ "test:types": "tsc"
65
+ }
66
+ }
package/src/auth.ts ADDED
@@ -0,0 +1,62 @@
1
+ import { VertexAuthError } from './errors'
2
+ import type { GeminiClientConfig } from '@tanstack/ai-gemini'
3
+
4
+ export type VertexClientConfig = Omit<
5
+ GeminiClientConfig,
6
+ 'vertexai' | 'enterprise'
7
+ >
8
+
9
+ export type VertexVideoConfig = VertexClientConfig & {
10
+ allowUrlFetch?: boolean
11
+ }
12
+
13
+ function nonEmpty(value: string | undefined): string | undefined {
14
+ if (value === undefined || value.length === 0) {
15
+ return undefined
16
+ }
17
+ return value
18
+ }
19
+
20
+ function readEnv(name: string): string | undefined {
21
+ if (typeof process === 'undefined' || process.env === undefined) {
22
+ return undefined
23
+ }
24
+ return nonEmpty(process.env[name])
25
+ }
26
+
27
+ /**
28
+ * Resolves Vertex Gemini client options.
29
+ *
30
+ * Factory fields win. Then env. Then ADC inside `@google/genai`.
31
+ * Does not read `GEMINI_API_KEY` or `GOOGLE_API_KEY`.
32
+ */
33
+ export function resolveVertexGeminiOptions(
34
+ config: VertexClientConfig = {},
35
+ ): GeminiClientConfig {
36
+ const project =
37
+ nonEmpty(config.project) ??
38
+ readEnv('GOOGLE_CLOUD_PROJECT') ??
39
+ readEnv('GOOGLE_VERTEX_PROJECT')
40
+ const location =
41
+ nonEmpty(config.location) ??
42
+ readEnv('GOOGLE_CLOUD_LOCATION') ??
43
+ readEnv('GOOGLE_VERTEX_LOCATION')
44
+ const apiKey = nonEmpty(config.apiKey) ?? readEnv('GOOGLE_VERTEX_API_KEY')
45
+
46
+ if (
47
+ apiKey === undefined &&
48
+ (project === undefined || location === undefined)
49
+ ) {
50
+ throw new VertexAuthError(
51
+ 'Vertex Gemini needs project and location, or an express apiKey. Pass project and location on the factory, or set GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION. For express mode, pass apiKey or set GOOGLE_VERTEX_API_KEY.',
52
+ )
53
+ }
54
+
55
+ return {
56
+ ...config,
57
+ vertexai: true,
58
+ ...(project === undefined ? {} : { project }),
59
+ ...(location === undefined ? {} : { location }),
60
+ ...(apiKey === undefined ? {} : { apiKey }),
61
+ }
62
+ }
package/src/errors.ts ADDED
@@ -0,0 +1,6 @@
1
+ export class VertexAuthError extends Error {
2
+ constructor(message: string) {
3
+ super(message)
4
+ this.name = 'VertexAuthError'
5
+ }
6
+ }
package/src/index.ts ADDED
@@ -0,0 +1,115 @@
1
+ import { ChatStreamSummarizeAdapter } from '@tanstack/ai/adapters'
2
+ import {
3
+ GeminiAudioAdapter,
4
+ GeminiEmbeddingAdapter,
5
+ GeminiImageAdapter,
6
+ GeminiTTSAdapter,
7
+ GeminiTextAdapter,
8
+ GeminiVideoAdapter,
9
+ } from '@tanstack/ai-gemini'
10
+ import { resolveVertexGeminiOptions } from './auth'
11
+ import type {
12
+ GeminiAudioModel,
13
+ GeminiEmbeddingModel,
14
+ GeminiImageModel,
15
+ GeminiTTSModels,
16
+ GeminiTextModel,
17
+ GeminiVideoModel,
18
+ } from '@tanstack/ai-gemini'
19
+ import type { VertexClientConfig, VertexVideoConfig } from './auth'
20
+
21
+ export { VertexAuthError } from './errors'
22
+ export {
23
+ resolveVertexGeminiOptions,
24
+ type VertexClientConfig,
25
+ type VertexVideoConfig,
26
+ } from './auth'
27
+
28
+ type GeminiTTSModel = (typeof GeminiTTSModels)[number]
29
+
30
+ function createVertex(config: VertexClientConfig = {}) {
31
+ const resolved = resolveVertexGeminiOptions(config)
32
+ return {
33
+ text<TModel extends GeminiTextModel>(model: TModel) {
34
+ return new GeminiTextAdapter(resolved, model)
35
+ },
36
+ summarize<TModel extends GeminiTextModel>(model: TModel) {
37
+ return new ChatStreamSummarizeAdapter(
38
+ new GeminiTextAdapter(resolved, model),
39
+ model,
40
+ 'gemini',
41
+ )
42
+ },
43
+ image<TModel extends GeminiImageModel>(model: TModel) {
44
+ return new GeminiImageAdapter(resolved, model)
45
+ },
46
+ embedding<TModel extends GeminiEmbeddingModel>(model: TModel) {
47
+ return new GeminiEmbeddingAdapter(resolved, model)
48
+ },
49
+ speech<TModel extends GeminiTTSModel>(model: TModel) {
50
+ return new GeminiTTSAdapter(resolved, model)
51
+ },
52
+ audio<TModel extends GeminiAudioModel>(model: TModel) {
53
+ return new GeminiAudioAdapter(resolved, model)
54
+ },
55
+ video<TModel extends GeminiVideoModel>(
56
+ model: TModel,
57
+ videoConfig?: Pick<VertexVideoConfig, 'allowUrlFetch'>,
58
+ ) {
59
+ return new GeminiVideoAdapter(
60
+ { ...resolved, allowUrlFetch: videoConfig?.allowUrlFetch },
61
+ model,
62
+ )
63
+ },
64
+ }
65
+ }
66
+
67
+ export function vertexText<TModel extends GeminiTextModel>(
68
+ model: TModel,
69
+ config: VertexClientConfig = {},
70
+ ): GeminiTextAdapter<TModel> {
71
+ return createVertex(config).text(model)
72
+ }
73
+
74
+ export function vertexSummarize<TModel extends GeminiTextModel>(
75
+ model: TModel,
76
+ config: VertexClientConfig = {},
77
+ ): ChatStreamSummarizeAdapter<TModel> {
78
+ return createVertex(config).summarize(model)
79
+ }
80
+
81
+ export function vertexImage<TModel extends GeminiImageModel>(
82
+ model: TModel,
83
+ config: VertexClientConfig = {},
84
+ ): GeminiImageAdapter<TModel> {
85
+ return createVertex(config).image(model)
86
+ }
87
+
88
+ export function vertexEmbedding<TModel extends GeminiEmbeddingModel>(
89
+ model: TModel,
90
+ config: VertexClientConfig = {},
91
+ ): GeminiEmbeddingAdapter<TModel> {
92
+ return createVertex(config).embedding(model)
93
+ }
94
+
95
+ export function vertexSpeech<TModel extends GeminiTTSModel>(
96
+ model: TModel,
97
+ config: VertexClientConfig = {},
98
+ ): GeminiTTSAdapter<TModel> {
99
+ return createVertex(config).speech(model)
100
+ }
101
+
102
+ export function vertexAudio<TModel extends GeminiAudioModel>(
103
+ model: TModel,
104
+ config: VertexClientConfig = {},
105
+ ): GeminiAudioAdapter<TModel> {
106
+ return createVertex(config).audio(model)
107
+ }
108
+
109
+ export function vertexVideo<TModel extends GeminiVideoModel>(
110
+ model: TModel,
111
+ config: VertexVideoConfig = {},
112
+ ): GeminiVideoAdapter<TModel> {
113
+ const { allowUrlFetch, ...client } = config
114
+ return createVertex(client).video(model, { allowUrlFetch })
115
+ }