@mhalder/qdrant-mcp-server 1.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/.env.example +92 -0
- package/.github/workflows/ci.yml +61 -0
- package/.github/workflows/claude-code-review.yml +57 -0
- package/.github/workflows/claude.yml +50 -0
- package/.github/workflows/release.yml +52 -0
- package/.husky/commit-msg +1 -0
- package/.husky/pre-commit +1 -0
- package/.releaserc.json +59 -0
- package/.yamlfmt +4 -0
- package/CHANGELOG.md +73 -0
- package/CONTRIBUTING.md +176 -0
- package/LICENSE +21 -0
- package/README.md +714 -0
- package/build/embeddings/base.d.ts +23 -0
- package/build/embeddings/base.d.ts.map +1 -0
- package/build/embeddings/base.js +2 -0
- package/build/embeddings/base.js.map +1 -0
- package/build/embeddings/cohere.d.ts +17 -0
- package/build/embeddings/cohere.d.ts.map +1 -0
- package/build/embeddings/cohere.js +102 -0
- package/build/embeddings/cohere.js.map +1 -0
- package/build/embeddings/cohere.test.d.ts +2 -0
- package/build/embeddings/cohere.test.d.ts.map +1 -0
- package/build/embeddings/cohere.test.js +279 -0
- package/build/embeddings/cohere.test.js.map +1 -0
- package/build/embeddings/factory.d.ts +10 -0
- package/build/embeddings/factory.d.ts.map +1 -0
- package/build/embeddings/factory.js +98 -0
- package/build/embeddings/factory.js.map +1 -0
- package/build/embeddings/factory.test.d.ts +2 -0
- package/build/embeddings/factory.test.d.ts.map +1 -0
- package/build/embeddings/factory.test.js +329 -0
- package/build/embeddings/factory.test.js.map +1 -0
- package/build/embeddings/ollama.d.ts +18 -0
- package/build/embeddings/ollama.d.ts.map +1 -0
- package/build/embeddings/ollama.js +135 -0
- package/build/embeddings/ollama.js.map +1 -0
- package/build/embeddings/ollama.test.d.ts +2 -0
- package/build/embeddings/ollama.test.d.ts.map +1 -0
- package/build/embeddings/ollama.test.js +399 -0
- package/build/embeddings/ollama.test.js.map +1 -0
- package/build/embeddings/openai.d.ts +16 -0
- package/build/embeddings/openai.d.ts.map +1 -0
- package/build/embeddings/openai.js +108 -0
- package/build/embeddings/openai.js.map +1 -0
- package/build/embeddings/openai.test.d.ts +2 -0
- package/build/embeddings/openai.test.d.ts.map +1 -0
- package/build/embeddings/openai.test.js +283 -0
- package/build/embeddings/openai.test.js.map +1 -0
- package/build/embeddings/voyage.d.ts +19 -0
- package/build/embeddings/voyage.d.ts.map +1 -0
- package/build/embeddings/voyage.js +113 -0
- package/build/embeddings/voyage.js.map +1 -0
- package/build/embeddings/voyage.test.d.ts +2 -0
- package/build/embeddings/voyage.test.d.ts.map +1 -0
- package/build/embeddings/voyage.test.js +371 -0
- package/build/embeddings/voyage.test.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +534 -0
- package/build/index.js.map +1 -0
- package/build/index.test.d.ts +2 -0
- package/build/index.test.d.ts.map +1 -0
- package/build/index.test.js +241 -0
- package/build/index.test.js.map +1 -0
- package/build/qdrant/client.d.ts +37 -0
- package/build/qdrant/client.d.ts.map +1 -0
- package/build/qdrant/client.js +142 -0
- package/build/qdrant/client.js.map +1 -0
- package/build/qdrant/client.test.d.ts +2 -0
- package/build/qdrant/client.test.d.ts.map +1 -0
- package/build/qdrant/client.test.js +340 -0
- package/build/qdrant/client.test.js.map +1 -0
- package/commitlint.config.js +25 -0
- package/docker-compose.yml +22 -0
- package/docs/test_report.md +259 -0
- package/examples/README.md +315 -0
- package/examples/basic/README.md +111 -0
- package/examples/filters/README.md +262 -0
- package/examples/knowledge-base/README.md +207 -0
- package/examples/rate-limiting/README.md +376 -0
- package/package.json +59 -0
- package/scripts/verify-providers.js +238 -0
- package/src/embeddings/base.ts +25 -0
- package/src/embeddings/cohere.test.ts +408 -0
- package/src/embeddings/cohere.ts +152 -0
- package/src/embeddings/factory.test.ts +453 -0
- package/src/embeddings/factory.ts +163 -0
- package/src/embeddings/ollama.test.ts +543 -0
- package/src/embeddings/ollama.ts +196 -0
- package/src/embeddings/openai.test.ts +402 -0
- package/src/embeddings/openai.ts +158 -0
- package/src/embeddings/voyage.test.ts +520 -0
- package/src/embeddings/voyage.ts +168 -0
- package/src/index.test.ts +304 -0
- package/src/index.ts +614 -0
- package/src/qdrant/client.test.ts +456 -0
- package/src/qdrant/client.ts +195 -0
- package/tsconfig.json +19 -0
- package/vitest.config.ts +37 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { OpenAIEmbeddings } from "./openai.js";
|
|
3
|
+
import OpenAI from "openai";
|
|
4
|
+
vi.mock("openai", () => ({
|
|
5
|
+
default: vi.fn(),
|
|
6
|
+
}));
|
|
7
|
+
describe("OpenAIEmbeddings", () => {
|
|
8
|
+
let embeddings;
|
|
9
|
+
let mockOpenAI;
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
mockOpenAI = {
|
|
12
|
+
embeddings: {
|
|
13
|
+
create: vi.fn(),
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
vi.mocked(OpenAI).mockImplementation(() => mockOpenAI);
|
|
17
|
+
embeddings = new OpenAIEmbeddings("test-api-key");
|
|
18
|
+
});
|
|
19
|
+
describe("constructor", () => {
|
|
20
|
+
it("should use default model and dimensions", () => {
|
|
21
|
+
expect(embeddings.getModel()).toBe("text-embedding-3-small");
|
|
22
|
+
expect(embeddings.getDimensions()).toBe(1536);
|
|
23
|
+
});
|
|
24
|
+
it("should use custom model", () => {
|
|
25
|
+
const customEmbeddings = new OpenAIEmbeddings("test-api-key", "text-embedding-3-large");
|
|
26
|
+
expect(customEmbeddings.getModel()).toBe("text-embedding-3-large");
|
|
27
|
+
expect(customEmbeddings.getDimensions()).toBe(3072);
|
|
28
|
+
});
|
|
29
|
+
it("should use custom dimensions", () => {
|
|
30
|
+
const customEmbeddings = new OpenAIEmbeddings("test-api-key", "text-embedding-3-small", 512);
|
|
31
|
+
expect(customEmbeddings.getDimensions()).toBe(512);
|
|
32
|
+
});
|
|
33
|
+
it("should use default dimensions for text-embedding-ada-002", () => {
|
|
34
|
+
const adaEmbeddings = new OpenAIEmbeddings("test-api-key", "text-embedding-ada-002");
|
|
35
|
+
expect(adaEmbeddings.getDimensions()).toBe(1536);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
describe("embed", () => {
|
|
39
|
+
it("should generate embedding for single text", async () => {
|
|
40
|
+
const mockEmbedding = Array(1536)
|
|
41
|
+
.fill(0)
|
|
42
|
+
.map((_, i) => i * 0.001);
|
|
43
|
+
mockOpenAI.embeddings.create.mockResolvedValue({
|
|
44
|
+
data: [{ embedding: mockEmbedding }],
|
|
45
|
+
});
|
|
46
|
+
const result = await embeddings.embed("test text");
|
|
47
|
+
expect(result).toEqual({
|
|
48
|
+
embedding: mockEmbedding,
|
|
49
|
+
dimensions: 1536,
|
|
50
|
+
});
|
|
51
|
+
expect(mockOpenAI.embeddings.create).toHaveBeenCalledWith({
|
|
52
|
+
model: "text-embedding-3-small",
|
|
53
|
+
input: "test text",
|
|
54
|
+
dimensions: 1536,
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
it("should handle long text", async () => {
|
|
58
|
+
const longText = "word ".repeat(1000);
|
|
59
|
+
const mockEmbedding = Array(1536).fill(0.5);
|
|
60
|
+
mockOpenAI.embeddings.create.mockResolvedValue({
|
|
61
|
+
data: [{ embedding: mockEmbedding }],
|
|
62
|
+
});
|
|
63
|
+
const result = await embeddings.embed(longText);
|
|
64
|
+
expect(result.embedding).toEqual(mockEmbedding);
|
|
65
|
+
expect(mockOpenAI.embeddings.create).toHaveBeenCalledWith({
|
|
66
|
+
model: "text-embedding-3-small",
|
|
67
|
+
input: longText,
|
|
68
|
+
dimensions: 1536,
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
it("should use custom model configuration", async () => {
|
|
72
|
+
const customEmbeddings = new OpenAIEmbeddings("test-api-key", "text-embedding-3-large", 3072);
|
|
73
|
+
const mockEmbedding = Array(3072).fill(0.1);
|
|
74
|
+
mockOpenAI.embeddings.create.mockResolvedValue({
|
|
75
|
+
data: [{ embedding: mockEmbedding }],
|
|
76
|
+
});
|
|
77
|
+
await customEmbeddings.embed("test");
|
|
78
|
+
expect(mockOpenAI.embeddings.create).toHaveBeenCalledWith({
|
|
79
|
+
model: "text-embedding-3-large",
|
|
80
|
+
input: "test",
|
|
81
|
+
dimensions: 3072,
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
it("should propagate errors", async () => {
|
|
85
|
+
mockOpenAI.embeddings.create.mockRejectedValue(new Error("API Error"));
|
|
86
|
+
await expect(embeddings.embed("test")).rejects.toThrow("API Error");
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
describe("embedBatch", () => {
|
|
90
|
+
it("should generate embeddings for multiple texts", async () => {
|
|
91
|
+
const mockEmbeddings = [
|
|
92
|
+
Array(1536).fill(0.1),
|
|
93
|
+
Array(1536).fill(0.2),
|
|
94
|
+
Array(1536).fill(0.3),
|
|
95
|
+
];
|
|
96
|
+
mockOpenAI.embeddings.create.mockResolvedValue({
|
|
97
|
+
data: [
|
|
98
|
+
{ embedding: mockEmbeddings[0] },
|
|
99
|
+
{ embedding: mockEmbeddings[1] },
|
|
100
|
+
{ embedding: mockEmbeddings[2] },
|
|
101
|
+
],
|
|
102
|
+
});
|
|
103
|
+
const texts = ["text1", "text2", "text3"];
|
|
104
|
+
const results = await embeddings.embedBatch(texts);
|
|
105
|
+
expect(results).toEqual([
|
|
106
|
+
{ embedding: mockEmbeddings[0], dimensions: 1536 },
|
|
107
|
+
{ embedding: mockEmbeddings[1], dimensions: 1536 },
|
|
108
|
+
{ embedding: mockEmbeddings[2], dimensions: 1536 },
|
|
109
|
+
]);
|
|
110
|
+
expect(mockOpenAI.embeddings.create).toHaveBeenCalledWith({
|
|
111
|
+
model: "text-embedding-3-small",
|
|
112
|
+
input: texts,
|
|
113
|
+
dimensions: 1536,
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
it("should handle empty batch", async () => {
|
|
117
|
+
mockOpenAI.embeddings.create.mockResolvedValue({
|
|
118
|
+
data: [],
|
|
119
|
+
});
|
|
120
|
+
const results = await embeddings.embedBatch([]);
|
|
121
|
+
expect(results).toEqual([]);
|
|
122
|
+
});
|
|
123
|
+
it("should handle single item in batch", async () => {
|
|
124
|
+
const mockEmbedding = Array(1536).fill(0.5);
|
|
125
|
+
mockOpenAI.embeddings.create.mockResolvedValue({
|
|
126
|
+
data: [{ embedding: mockEmbedding }],
|
|
127
|
+
});
|
|
128
|
+
const results = await embeddings.embedBatch(["single text"]);
|
|
129
|
+
expect(results).toHaveLength(1);
|
|
130
|
+
expect(results[0].embedding).toEqual(mockEmbedding);
|
|
131
|
+
});
|
|
132
|
+
it("should handle large batches", async () => {
|
|
133
|
+
const batchSize = 100;
|
|
134
|
+
const mockEmbeddings = Array(batchSize)
|
|
135
|
+
.fill(null)
|
|
136
|
+
.map(() => Array(1536).fill(Math.random()));
|
|
137
|
+
mockOpenAI.embeddings.create.mockResolvedValue({
|
|
138
|
+
data: mockEmbeddings.map((embedding) => ({ embedding })),
|
|
139
|
+
});
|
|
140
|
+
const texts = Array(batchSize)
|
|
141
|
+
.fill(null)
|
|
142
|
+
.map((_, i) => `text ${i}`);
|
|
143
|
+
const results = await embeddings.embedBatch(texts);
|
|
144
|
+
expect(results).toHaveLength(batchSize);
|
|
145
|
+
});
|
|
146
|
+
it("should propagate errors in batch", async () => {
|
|
147
|
+
mockOpenAI.embeddings.create.mockRejectedValue(new Error("Batch API Error"));
|
|
148
|
+
await expect(embeddings.embedBatch(["text1", "text2"])).rejects.toThrow("Batch API Error");
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
describe("getDimensions", () => {
|
|
152
|
+
it("should return configured dimensions", () => {
|
|
153
|
+
expect(embeddings.getDimensions()).toBe(1536);
|
|
154
|
+
});
|
|
155
|
+
it("should return custom dimensions", () => {
|
|
156
|
+
const customEmbeddings = new OpenAIEmbeddings("test-api-key", "text-embedding-3-small", 512);
|
|
157
|
+
expect(customEmbeddings.getDimensions()).toBe(512);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
describe("getModel", () => {
|
|
161
|
+
it("should return configured model", () => {
|
|
162
|
+
expect(embeddings.getModel()).toBe("text-embedding-3-small");
|
|
163
|
+
});
|
|
164
|
+
it("should return custom model", () => {
|
|
165
|
+
const customEmbeddings = new OpenAIEmbeddings("test-api-key", "text-embedding-3-large");
|
|
166
|
+
expect(customEmbeddings.getModel()).toBe("text-embedding-3-large");
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
describe("rate limiting", () => {
|
|
170
|
+
it("should retry on rate limit error (429 status)", async () => {
|
|
171
|
+
const mockEmbedding = Array(1536).fill(0.5);
|
|
172
|
+
// Fail first two times with rate limit, succeed on third
|
|
173
|
+
mockOpenAI.embeddings.create
|
|
174
|
+
.mockRejectedValueOnce({ status: 429, message: "Rate limit exceeded" })
|
|
175
|
+
.mockRejectedValueOnce({ status: 429, message: "Rate limit exceeded" })
|
|
176
|
+
.mockResolvedValue({ data: [{ embedding: mockEmbedding }] });
|
|
177
|
+
const result = await embeddings.embed("test text");
|
|
178
|
+
expect(result.embedding).toEqual(mockEmbedding);
|
|
179
|
+
expect(mockOpenAI.embeddings.create).toHaveBeenCalledTimes(3);
|
|
180
|
+
});
|
|
181
|
+
it("should respect Retry-After header when present", async () => {
|
|
182
|
+
const mockEmbedding = Array(1536).fill(0.5);
|
|
183
|
+
const rateLimitError = {
|
|
184
|
+
status: 429,
|
|
185
|
+
message: "Rate limit exceeded",
|
|
186
|
+
headers: { "retry-after": "2" },
|
|
187
|
+
};
|
|
188
|
+
mockOpenAI.embeddings.create
|
|
189
|
+
.mockRejectedValueOnce(rateLimitError)
|
|
190
|
+
.mockResolvedValue({ data: [{ embedding: mockEmbedding }] });
|
|
191
|
+
const startTime = Date.now();
|
|
192
|
+
await embeddings.embed("test text");
|
|
193
|
+
const duration = Date.now() - startTime;
|
|
194
|
+
// Should wait at least 2 seconds (2000ms)
|
|
195
|
+
expect(duration).toBeGreaterThanOrEqual(1900); // Allow small margin
|
|
196
|
+
});
|
|
197
|
+
it("should fallback to exponential backoff with invalid Retry-After header", async () => {
|
|
198
|
+
const rateLimitEmbeddings = new OpenAIEmbeddings("test-api-key", "text-embedding-3-small", undefined, {
|
|
199
|
+
retryAttempts: 2,
|
|
200
|
+
retryDelayMs: 100, // 100ms for faster tests
|
|
201
|
+
});
|
|
202
|
+
const mockEmbedding = Array(1536).fill(0.5);
|
|
203
|
+
// Test various invalid Retry-After values
|
|
204
|
+
const invalidRetryAfterError = {
|
|
205
|
+
status: 429,
|
|
206
|
+
message: "Rate limit exceeded",
|
|
207
|
+
headers: { "retry-after": "invalid" }, // Non-numeric value
|
|
208
|
+
};
|
|
209
|
+
mockOpenAI.embeddings.create
|
|
210
|
+
.mockRejectedValueOnce(invalidRetryAfterError)
|
|
211
|
+
.mockResolvedValue({ data: [{ embedding: mockEmbedding }] });
|
|
212
|
+
const startTime = Date.now();
|
|
213
|
+
await rateLimitEmbeddings.embed("test text");
|
|
214
|
+
const duration = Date.now() - startTime;
|
|
215
|
+
// Should fallback to exponential backoff (100ms) instead of using invalid header
|
|
216
|
+
expect(duration).toBeGreaterThanOrEqual(90); // Allow small margin
|
|
217
|
+
expect(duration).toBeLessThan(500); // Should not wait too long
|
|
218
|
+
});
|
|
219
|
+
it("should use exponential backoff when no Retry-After header", async () => {
|
|
220
|
+
const rateLimitEmbeddings = new OpenAIEmbeddings("test-api-key", "text-embedding-3-small", undefined, {
|
|
221
|
+
retryAttempts: 3,
|
|
222
|
+
retryDelayMs: 100, // 100ms for faster tests
|
|
223
|
+
});
|
|
224
|
+
const mockEmbedding = Array(1536).fill(0.5);
|
|
225
|
+
const rateLimitError = {
|
|
226
|
+
status: 429,
|
|
227
|
+
message: "Rate limit exceeded",
|
|
228
|
+
};
|
|
229
|
+
mockOpenAI.embeddings.create
|
|
230
|
+
.mockRejectedValueOnce(rateLimitError)
|
|
231
|
+
.mockRejectedValueOnce(rateLimitError)
|
|
232
|
+
.mockResolvedValue({ data: [{ embedding: mockEmbedding }] });
|
|
233
|
+
const startTime = Date.now();
|
|
234
|
+
await rateLimitEmbeddings.embed("test text");
|
|
235
|
+
const duration = Date.now() - startTime;
|
|
236
|
+
// Should wait: 100ms (first retry) + 200ms (second retry) = 300ms
|
|
237
|
+
expect(duration).toBeGreaterThanOrEqual(250); // Allow margin for test execution
|
|
238
|
+
});
|
|
239
|
+
it("should throw error after max retries exceeded", async () => {
|
|
240
|
+
const rateLimitEmbeddings = new OpenAIEmbeddings("test-api-key", "text-embedding-3-small", undefined, {
|
|
241
|
+
retryAttempts: 2,
|
|
242
|
+
retryDelayMs: 100,
|
|
243
|
+
});
|
|
244
|
+
const rateLimitError = {
|
|
245
|
+
status: 429,
|
|
246
|
+
message: "Rate limit exceeded",
|
|
247
|
+
};
|
|
248
|
+
mockOpenAI.embeddings.create.mockRejectedValue(rateLimitError);
|
|
249
|
+
await expect(rateLimitEmbeddings.embed("test text")).rejects.toThrow("OpenAI API rate limit exceeded after 2 retry attempts");
|
|
250
|
+
// Should try initial + 2 retries = 3 total attempts
|
|
251
|
+
expect(mockOpenAI.embeddings.create).toHaveBeenCalledTimes(3);
|
|
252
|
+
});
|
|
253
|
+
it("should handle rate limit errors in batch operations", async () => {
|
|
254
|
+
const mockEmbeddings = [Array(1536).fill(0.1), Array(1536).fill(0.2)];
|
|
255
|
+
mockOpenAI.embeddings.create
|
|
256
|
+
.mockRejectedValueOnce({ status: 429, message: "Rate limit exceeded" })
|
|
257
|
+
.mockResolvedValue({
|
|
258
|
+
data: [
|
|
259
|
+
{ embedding: mockEmbeddings[0] },
|
|
260
|
+
{ embedding: mockEmbeddings[1] },
|
|
261
|
+
],
|
|
262
|
+
});
|
|
263
|
+
const results = await embeddings.embedBatch(["text1", "text2"]);
|
|
264
|
+
expect(results).toHaveLength(2);
|
|
265
|
+
expect(mockOpenAI.embeddings.create).toHaveBeenCalledTimes(2);
|
|
266
|
+
});
|
|
267
|
+
it("should not retry on non-rate-limit errors", async () => {
|
|
268
|
+
const apiError = new Error("Invalid API key");
|
|
269
|
+
mockOpenAI.embeddings.create.mockRejectedValue(apiError);
|
|
270
|
+
await expect(embeddings.embed("test text")).rejects.toThrow("Invalid API key");
|
|
271
|
+
expect(mockOpenAI.embeddings.create).toHaveBeenCalledTimes(1);
|
|
272
|
+
});
|
|
273
|
+
it("should accept custom rate limit configuration", () => {
|
|
274
|
+
const customEmbeddings = new OpenAIEmbeddings("test-api-key", "text-embedding-3-small", undefined, {
|
|
275
|
+
maxRequestsPerMinute: 1000,
|
|
276
|
+
retryAttempts: 5,
|
|
277
|
+
retryDelayMs: 2000,
|
|
278
|
+
});
|
|
279
|
+
expect(customEmbeddings).toBeDefined();
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
//# sourceMappingURL=openai.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.test.js","sourceRoot":"","sources":["../../src/embeddings/openai.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { EmbeddingProvider, EmbeddingResult, RateLimitConfig } from "./base.js";
|
|
2
|
+
export declare class VoyageEmbeddings implements EmbeddingProvider {
|
|
3
|
+
private apiKey;
|
|
4
|
+
private model;
|
|
5
|
+
private dimensions;
|
|
6
|
+
private limiter;
|
|
7
|
+
private retryAttempts;
|
|
8
|
+
private retryDelayMs;
|
|
9
|
+
private baseUrl;
|
|
10
|
+
private inputType?;
|
|
11
|
+
constructor(apiKey: string, model?: string, dimensions?: number, rateLimitConfig?: RateLimitConfig, baseUrl?: string, inputType?: "query" | "document");
|
|
12
|
+
private retryWithBackoff;
|
|
13
|
+
private callApi;
|
|
14
|
+
embed(text: string): Promise<EmbeddingResult>;
|
|
15
|
+
embedBatch(texts: string[]): Promise<EmbeddingResult[]>;
|
|
16
|
+
getDimensions(): number;
|
|
17
|
+
getModel(): string;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=voyage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voyage.d.ts","sourceRoot":"","sources":["../../src/embeddings/voyage.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAehF,qBAAa,gBAAiB,YAAW,iBAAiB;IACxD,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAC,CAAuB;gBAGvC,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,MAAmB,EAC1B,UAAU,CAAC,EAAE,MAAM,EACnB,eAAe,CAAC,EAAE,eAAe,EACjC,OAAO,GAAE,MAAsC,EAC/C,SAAS,CAAC,EAAE,OAAO,GAAG,UAAU;YA+BpB,gBAAgB;YAiChB,OAAO;IA8Bf,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAiB7C,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAiB7D,aAAa,IAAI,MAAM;IAIvB,QAAQ,IAAI,MAAM;CAGnB"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import Bottleneck from "bottleneck";
|
|
2
|
+
export class VoyageEmbeddings {
|
|
3
|
+
apiKey;
|
|
4
|
+
model;
|
|
5
|
+
dimensions;
|
|
6
|
+
limiter;
|
|
7
|
+
retryAttempts;
|
|
8
|
+
retryDelayMs;
|
|
9
|
+
baseUrl;
|
|
10
|
+
inputType;
|
|
11
|
+
constructor(apiKey, model = "voyage-2", dimensions, rateLimitConfig, baseUrl = "https://api.voyageai.com/v1", inputType) {
|
|
12
|
+
this.apiKey = apiKey;
|
|
13
|
+
this.model = model;
|
|
14
|
+
this.baseUrl = baseUrl;
|
|
15
|
+
this.inputType = inputType;
|
|
16
|
+
// Default dimensions for different models
|
|
17
|
+
const defaultDimensions = {
|
|
18
|
+
"voyage-2": 1024,
|
|
19
|
+
"voyage-large-2": 1536,
|
|
20
|
+
"voyage-code-2": 1536,
|
|
21
|
+
"voyage-lite-02-instruct": 1024,
|
|
22
|
+
};
|
|
23
|
+
this.dimensions = dimensions || defaultDimensions[model] || 1024;
|
|
24
|
+
// Rate limiting configuration
|
|
25
|
+
const maxRequestsPerMinute = rateLimitConfig?.maxRequestsPerMinute || 300;
|
|
26
|
+
this.retryAttempts = rateLimitConfig?.retryAttempts || 3;
|
|
27
|
+
this.retryDelayMs = rateLimitConfig?.retryDelayMs || 1000;
|
|
28
|
+
this.limiter = new Bottleneck({
|
|
29
|
+
reservoir: maxRequestsPerMinute,
|
|
30
|
+
reservoirRefreshAmount: maxRequestsPerMinute,
|
|
31
|
+
reservoirRefreshInterval: 60 * 1000,
|
|
32
|
+
maxConcurrent: 5,
|
|
33
|
+
minTime: Math.floor((60 * 1000) / maxRequestsPerMinute),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
async retryWithBackoff(fn, attempt = 0) {
|
|
37
|
+
try {
|
|
38
|
+
return await fn();
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
const apiError = error;
|
|
42
|
+
const isRateLimitError = apiError?.status === 429 ||
|
|
43
|
+
apiError?.message?.toLowerCase().includes("rate limit");
|
|
44
|
+
if (isRateLimitError && attempt < this.retryAttempts) {
|
|
45
|
+
const delayMs = this.retryDelayMs * Math.pow(2, attempt);
|
|
46
|
+
const waitTimeSeconds = (delayMs / 1000).toFixed(1);
|
|
47
|
+
console.error(`Rate limit reached. Retrying in ${waitTimeSeconds}s (attempt ${attempt + 1}/${this.retryAttempts})...`);
|
|
48
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
49
|
+
return this.retryWithBackoff(fn, attempt + 1);
|
|
50
|
+
}
|
|
51
|
+
if (isRateLimitError) {
|
|
52
|
+
throw new Error(`Voyage AI API rate limit exceeded after ${this.retryAttempts} retry attempts. Please try again later or reduce request frequency.`);
|
|
53
|
+
}
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async callApi(texts) {
|
|
58
|
+
const body = {
|
|
59
|
+
input: texts,
|
|
60
|
+
model: this.model,
|
|
61
|
+
};
|
|
62
|
+
if (this.inputType) {
|
|
63
|
+
body.input_type = this.inputType;
|
|
64
|
+
}
|
|
65
|
+
const response = await fetch(`${this.baseUrl}/embeddings`, {
|
|
66
|
+
method: "POST",
|
|
67
|
+
headers: {
|
|
68
|
+
"Content-Type": "application/json",
|
|
69
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
70
|
+
},
|
|
71
|
+
body: JSON.stringify(body),
|
|
72
|
+
});
|
|
73
|
+
if (!response.ok) {
|
|
74
|
+
const error = {
|
|
75
|
+
status: response.status,
|
|
76
|
+
message: await response.text(),
|
|
77
|
+
};
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
return response.json();
|
|
81
|
+
}
|
|
82
|
+
async embed(text) {
|
|
83
|
+
return this.limiter.schedule(() => this.retryWithBackoff(async () => {
|
|
84
|
+
const response = await this.callApi([text]);
|
|
85
|
+
if (!response.data || response.data.length === 0) {
|
|
86
|
+
throw new Error("No embedding returned from Voyage AI API");
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
embedding: response.data[0].embedding,
|
|
90
|
+
dimensions: this.dimensions,
|
|
91
|
+
};
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
async embedBatch(texts) {
|
|
95
|
+
return this.limiter.schedule(() => this.retryWithBackoff(async () => {
|
|
96
|
+
const response = await this.callApi(texts);
|
|
97
|
+
if (!response.data) {
|
|
98
|
+
throw new Error("No embeddings returned from Voyage AI API");
|
|
99
|
+
}
|
|
100
|
+
return response.data.map((item) => ({
|
|
101
|
+
embedding: item.embedding,
|
|
102
|
+
dimensions: this.dimensions,
|
|
103
|
+
}));
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
getDimensions() {
|
|
107
|
+
return this.dimensions;
|
|
108
|
+
}
|
|
109
|
+
getModel() {
|
|
110
|
+
return this.model;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=voyage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voyage.js","sourceRoot":"","sources":["../../src/embeddings/voyage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voyage.test.d.ts","sourceRoot":"","sources":["../../src/embeddings/voyage.test.ts"],"names":[],"mappings":""}
|