@ai-sdk/google-vertex 4.0.27 → 4.0.29

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.
@@ -1,315 +0,0 @@
1
- import {
2
- EmbeddingModelV3Embedding,
3
- TooManyEmbeddingValuesForCallError,
4
- } from '@ai-sdk/provider';
5
- import { createTestServer } from '@ai-sdk/test-server/with-vitest';
6
- import { GoogleVertexEmbeddingModel } from './google-vertex-embedding-model';
7
- import { describe, it, expect, vi } from 'vitest';
8
- import { createVertex } from './google-vertex-provider';
9
-
10
- vi.mock('./version', () => ({
11
- VERSION: '0.0.0-test',
12
- }));
13
-
14
- const dummyEmbeddings = [
15
- [0.1, 0.2, 0.3],
16
- [0.4, 0.5, 0.6],
17
- ];
18
- const testValues = ['test text one', 'test text two'];
19
-
20
- const DEFAULT_URL =
21
- 'https://us-central1-aiplatform.googleapis.com/v1beta1/projects/test-project/locations/us-central1/publishers/google/models/textembedding-gecko@001:predict';
22
-
23
- const CUSTOM_URL =
24
- 'https://custom-endpoint.com/models/textembedding-gecko@001:predict';
25
-
26
- const server = createTestServer({
27
- [DEFAULT_URL]: {},
28
- [CUSTOM_URL]: {},
29
- });
30
-
31
- describe('GoogleVertexEmbeddingModel', () => {
32
- const mockModelId = 'textembedding-gecko@001';
33
- const mockProviderOptions = {
34
- outputDimensionality: 768,
35
- taskType: 'SEMANTIC_SIMILARITY',
36
- title: 'test title',
37
- autoTruncate: false,
38
- };
39
-
40
- const mockConfig = {
41
- provider: 'google-vertex',
42
- region: 'us-central1',
43
- project: 'test-project',
44
- headers: () => ({}),
45
- baseURL:
46
- 'https://us-central1-aiplatform.googleapis.com/v1beta1/projects/test-project/locations/us-central1/publishers/google',
47
- };
48
-
49
- const model = new GoogleVertexEmbeddingModel(mockModelId, mockConfig);
50
-
51
- function prepareJsonResponse({
52
- embeddings = dummyEmbeddings,
53
- tokenCounts = [1, 1],
54
- headers,
55
- }: {
56
- embeddings?: EmbeddingModelV3Embedding[];
57
- tokenCounts?: number[];
58
- headers?: Record<string, string>;
59
- } = {}) {
60
- server.urls[DEFAULT_URL].response = {
61
- type: 'json-value',
62
- headers,
63
- body: {
64
- predictions: embeddings.map((values, i) => ({
65
- embeddings: {
66
- values,
67
- statistics: { token_count: tokenCounts[i] },
68
- },
69
- })),
70
- },
71
- };
72
- }
73
-
74
- it('should extract embeddings', async () => {
75
- prepareJsonResponse();
76
-
77
- const { embeddings } = await model.doEmbed({
78
- values: testValues,
79
- providerOptions: { google: mockProviderOptions },
80
- });
81
-
82
- expect(embeddings).toStrictEqual(dummyEmbeddings);
83
- });
84
-
85
- it('should expose the raw response', async () => {
86
- prepareJsonResponse({
87
- headers: {
88
- 'test-header': 'test-value',
89
- },
90
- });
91
-
92
- const { response } = await model.doEmbed({
93
- values: testValues,
94
- providerOptions: { google: mockProviderOptions },
95
- });
96
-
97
- expect(response?.headers).toStrictEqual({
98
- // default headers:
99
- 'content-length': '159',
100
- 'content-type': 'application/json',
101
- // custom header
102
- 'test-header': 'test-value',
103
- });
104
- expect(response).toMatchSnapshot();
105
- });
106
-
107
- it('should extract usage', async () => {
108
- prepareJsonResponse({
109
- tokenCounts: [10, 15],
110
- });
111
-
112
- const { usage } = await model.doEmbed({
113
- values: testValues,
114
- providerOptions: { google: mockProviderOptions },
115
- });
116
-
117
- expect(usage).toStrictEqual({ tokens: 25 });
118
- });
119
-
120
- it('should pass the model parameters correctly', async () => {
121
- prepareJsonResponse();
122
-
123
- await model.doEmbed({
124
- values: testValues,
125
- providerOptions: { google: mockProviderOptions },
126
- });
127
-
128
- expect(await server.calls[0].requestBodyJson).toStrictEqual({
129
- instances: testValues.map(value => ({
130
- content: value,
131
- task_type: mockProviderOptions.taskType,
132
- title: mockProviderOptions.title,
133
- })),
134
- parameters: {
135
- outputDimensionality: mockProviderOptions.outputDimensionality,
136
- autoTruncate: mockProviderOptions.autoTruncate,
137
- },
138
- });
139
- });
140
-
141
- it('should accept vertex as provider options key', async () => {
142
- prepareJsonResponse();
143
-
144
- await model.doEmbed({
145
- values: testValues,
146
- providerOptions: { vertex: mockProviderOptions },
147
- });
148
-
149
- expect(await server.calls[0].requestBodyJson).toStrictEqual({
150
- instances: testValues.map(value => ({
151
- content: value,
152
- task_type: mockProviderOptions.taskType,
153
- title: mockProviderOptions.title,
154
- })),
155
- parameters: {
156
- outputDimensionality: mockProviderOptions.outputDimensionality,
157
- autoTruncate: mockProviderOptions.autoTruncate,
158
- },
159
- });
160
- });
161
-
162
- it('should pass the taskType setting in instances', async () => {
163
- prepareJsonResponse();
164
-
165
- await model.doEmbed({
166
- values: testValues,
167
- providerOptions: { google: { taskType: mockProviderOptions.taskType } },
168
- });
169
-
170
- expect(await server.calls[0].requestBodyJson).toStrictEqual({
171
- instances: testValues.map(value => ({
172
- content: value,
173
- task_type: mockProviderOptions.taskType,
174
- })),
175
- parameters: {},
176
- });
177
- });
178
-
179
- it('should pass the title setting in instances', async () => {
180
- prepareJsonResponse();
181
-
182
- await model.doEmbed({
183
- values: testValues,
184
- providerOptions: { google: { title: mockProviderOptions.title } },
185
- });
186
-
187
- expect(await server.calls[0].requestBodyJson).toStrictEqual({
188
- instances: testValues.map(value => ({
189
- content: value,
190
- title: mockProviderOptions.title,
191
- })),
192
- parameters: {},
193
- });
194
- });
195
-
196
- // changed test to go through the provider `createVertex`
197
- it('should pass headers correctly', async () => {
198
- prepareJsonResponse();
199
-
200
- const provider = createVertex({
201
- project: 'test-project',
202
- location: 'us-central1',
203
- headers: { 'X-Custom-Header': 'custom-value' },
204
- });
205
-
206
- await provider.embeddingModel(mockModelId).doEmbed({
207
- values: testValues,
208
- headers: { 'X-Request-Header': 'request-value' },
209
- providerOptions: { google: mockProviderOptions },
210
- });
211
-
212
- expect(server.calls[0].requestHeaders).toStrictEqual({
213
- 'content-type': 'application/json',
214
- 'x-custom-header': 'custom-value',
215
- 'x-request-header': 'request-value',
216
- });
217
- expect(server.calls[0].requestUserAgent).toContain(
218
- `ai-sdk/google-vertex/0.0.0-test`,
219
- );
220
- });
221
-
222
- it('should throw TooManyEmbeddingValuesForCallError when too many values provided', async () => {
223
- const tooManyValues = Array(2049).fill('test');
224
-
225
- await expect(
226
- model.doEmbed({
227
- values: tooManyValues,
228
- providerOptions: { google: mockProviderOptions },
229
- }),
230
- ).rejects.toThrow(TooManyEmbeddingValuesForCallError);
231
- });
232
-
233
- it('should use custom baseURL when provided', async () => {
234
- server.urls[CUSTOM_URL].response = {
235
- type: 'json-value',
236
- body: {
237
- predictions: dummyEmbeddings.map(values => ({
238
- embeddings: {
239
- values,
240
- statistics: { token_count: 1 },
241
- },
242
- })),
243
- },
244
- };
245
-
246
- const modelWithCustomUrl = new GoogleVertexEmbeddingModel(
247
- 'textembedding-gecko@001',
248
- {
249
- headers: () => ({}),
250
- baseURL: 'https://custom-endpoint.com',
251
- provider: 'google-vertex',
252
- },
253
- );
254
-
255
- const response = await modelWithCustomUrl.doEmbed({
256
- values: testValues,
257
- providerOptions: {
258
- google: { outputDimensionality: 768 },
259
- },
260
- });
261
-
262
- expect(response.embeddings).toStrictEqual(dummyEmbeddings);
263
-
264
- expect(server.calls[0].requestUrl).toBe(
265
- 'https://custom-endpoint.com/models/textembedding-gecko@001:predict',
266
- );
267
- });
268
-
269
- it('should use custom fetch when provided and include proper request content', async () => {
270
- const customFetch = vi.fn().mockResolvedValue(
271
- new Response(
272
- JSON.stringify({
273
- predictions: dummyEmbeddings.map(values => ({
274
- embeddings: {
275
- values,
276
- statistics: { token_count: 1 },
277
- },
278
- })),
279
- }),
280
- ),
281
- );
282
-
283
- const modelWithCustomFetch = new GoogleVertexEmbeddingModel(
284
- 'textembedding-gecko@001',
285
-
286
- {
287
- headers: () => ({}),
288
- baseURL: 'https://custom-endpoint.com',
289
- provider: 'google-vertex',
290
- fetch: customFetch,
291
- },
292
- );
293
-
294
- const response = await modelWithCustomFetch.doEmbed({
295
- values: testValues,
296
- providerOptions: {
297
- google: { outputDimensionality: 768 },
298
- },
299
- });
300
-
301
- expect(response.embeddings).toStrictEqual(dummyEmbeddings);
302
-
303
- expect(customFetch).toHaveBeenCalledWith(CUSTOM_URL, expect.any(Object));
304
-
305
- const [_, secondArgument] = customFetch.mock.calls[0];
306
- const requestBody = JSON.parse(secondArgument.body);
307
-
308
- expect(requestBody).toStrictEqual({
309
- instances: testValues.map(value => ({ content: value })),
310
- parameters: {
311
- outputDimensionality: 768,
312
- },
313
- });
314
- });
315
- });