embedding-deepinfra.test.mjs
227 lines 6.8 KB
Raw
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor ⚠ breaking 1 day ago
1 /**
2 * DeepInfra OpenAI-compatible embeddings (lib/embedding.mjs).
3 *
4 * Verifies wire shape (POST to https://api.deepinfra.com/v1/openai/embeddings),
5 * vector ordering by index (matches OpenAI behaviour), token-usage extraction,
6 * and dimension defaults for common DeepInfra embedding models.
7 */
8 import { describe, it, beforeEach, afterEach } from 'node:test';
9 import assert from 'node:assert';
10 import {
11 embedWithUsage,
12 embeddingDimension,
13 formatEmbeddingFetchFailure,
14 } from '../lib/embedding.mjs';
15
16 const origFetch = globalThis.fetch;
17 const origDeepinfra = process.env.DEEPINFRA_API_KEY;
18
19 function restoreEnv() {
20 if (origDeepinfra === undefined) delete process.env.DEEPINFRA_API_KEY;
21 else process.env.DEEPINFRA_API_KEY = origDeepinfra;
22 }
23
24 describe('embedWithUsage provider=deepinfra', () => {
25 beforeEach(() => {
26 delete process.env.DEEPINFRA_API_KEY;
27 });
28
29 afterEach(() => {
30 globalThis.fetch = origFetch;
31 restoreEnv();
32 });
33
34 it('throws when DEEPINFRA_API_KEY is not set', async () => {
35 await assert.rejects(
36 () =>
37 embedWithUsage(['hello'], { provider: 'deepinfra', model: 'BAAI/bge-large-en-v1.5' }),
38 /DEEPINFRA_API_KEY/,
39 );
40 });
41
42 it('posts to the DeepInfra OpenAI-compat endpoint with bearer token and model', async () => {
43 process.env.DEEPINFRA_API_KEY = 'di-test';
44 let observedUrl = '';
45 let observedHeaders;
46 let observedBody;
47 globalThis.fetch = async (url, init) => {
48 observedUrl = String(url);
49 observedHeaders = init.headers;
50 observedBody = JSON.parse(init.body);
51 return {
52 ok: true,
53 json: async () => ({
54 data: [
55 { index: 0, embedding: [0.1, 0.2] },
56 { index: 1, embedding: [0.3, 0.4] },
57 ],
58 usage: { prompt_tokens: 7 },
59 }),
60 };
61 };
62 const r = await embedWithUsage(
63 ['alpha', 'beta'],
64 { provider: 'deepinfra', model: 'BAAI/bge-large-en-v1.5' },
65 );
66 assert.strictEqual(observedUrl, 'https://api.deepinfra.com/v1/openai/embeddings');
67 assert.strictEqual(observedHeaders.Authorization, 'Bearer di-test');
68 assert.strictEqual(observedBody.model, 'BAAI/bge-large-en-v1.5');
69 assert.deepStrictEqual(observedBody.input, ['alpha', 'beta']);
70 assert.deepStrictEqual(r.vectors, [
71 [0.1, 0.2],
72 [0.3, 0.4],
73 ]);
74 assert.strictEqual(r.embedding_input_tokens, 7);
75 });
76
77 it('sorts vectors by index even when API returns out of order', async () => {
78 process.env.DEEPINFRA_API_KEY = 'di-test';
79 globalThis.fetch = async () => ({
80 ok: true,
81 json: async () => ({
82 data: [
83 { index: 1, embedding: [0.3, 0.4] },
84 { index: 0, embedding: [0.1, 0.2] },
85 ],
86 usage: { prompt_tokens: 5 },
87 }),
88 });
89 const r = await embedWithUsage(
90 ['first', 'second'],
91 { provider: 'deepinfra', model: 'BAAI/bge-large-en-v1.5' },
92 );
93 assert.deepStrictEqual(r.vectors, [
94 [0.1, 0.2],
95 [0.3, 0.4],
96 ]);
97 });
98
99 it('falls back to total_tokens when prompt_tokens is missing, then to estimate', async () => {
100 process.env.DEEPINFRA_API_KEY = 'di-test';
101 globalThis.fetch = async () => ({
102 ok: true,
103 json: async () => ({
104 data: [{ index: 0, embedding: [0.1] }],
105 usage: { total_tokens: 9 },
106 }),
107 });
108 const r = await embedWithUsage(['x'], {
109 provider: 'deepinfra',
110 model: 'BAAI/bge-large-en-v1.5',
111 });
112 assert.strictEqual(r.embedding_input_tokens, 9);
113
114 globalThis.fetch = async () => ({
115 ok: true,
116 json: async () => ({
117 data: [{ index: 0, embedding: [0.1] }],
118 }),
119 });
120 const r2 = await embedWithUsage(['hello world'], {
121 provider: 'deepinfra',
122 model: 'BAAI/bge-large-en-v1.5',
123 });
124 // 'hello world'.length = 11 chars → ceil(11/4) = 3 tokens
125 assert.strictEqual(r2.embedding_input_tokens, 3);
126 });
127
128 it('uses default model BAAI/bge-large-en-v1.5 when model is unset', async () => {
129 process.env.DEEPINFRA_API_KEY = 'di-test';
130 let observedModel;
131 globalThis.fetch = async (url, init) => {
132 observedModel = JSON.parse(init.body).model;
133 return {
134 ok: true,
135 json: async () => ({ data: [{ index: 0, embedding: [0.1] }] }),
136 };
137 };
138 await embedWithUsage(['x'], { provider: 'deepinfra' });
139 assert.strictEqual(observedModel, 'BAAI/bge-large-en-v1.5');
140 });
141
142 it('surfaces non-2xx response with status and body in error', async () => {
143 process.env.DEEPINFRA_API_KEY = 'di-test';
144 globalThis.fetch = async () => ({
145 ok: false,
146 status: 401,
147 text: async () => 'invalid api key',
148 });
149 await assert.rejects(
150 () =>
151 embedWithUsage(['x'], { provider: 'deepinfra', model: 'BAAI/bge-large-en-v1.5' }),
152 /DeepInfra embed failed \(401\): invalid api key/,
153 );
154 });
155 });
156
157 describe('embeddingDimension provider=deepinfra', () => {
158 it('default BAAI/bge-large-en-v1.5 is 1024', () => {
159 assert.strictEqual(
160 embeddingDimension({ provider: 'deepinfra', model: 'BAAI/bge-large-en-v1.5' }),
161 1024,
162 );
163 });
164
165 it('Qwen3-Embedding-8B is 4096', () => {
166 assert.strictEqual(
167 embeddingDimension({ provider: 'deepinfra', model: 'Qwen/Qwen3-Embedding-8B' }),
168 4096,
169 );
170 });
171
172 it('Qwen3-Embedding-4B is 2560', () => {
173 assert.strictEqual(
174 embeddingDimension({ provider: 'deepinfra', model: 'Qwen/Qwen3-Embedding-4B' }),
175 2560,
176 );
177 });
178
179 it('multilingual-e5-large-instruct is 1024', () => {
180 assert.strictEqual(
181 embeddingDimension({
182 provider: 'deepinfra',
183 model: 'intfloat/multilingual-e5-large-instruct',
184 }),
185 1024,
186 );
187 });
188
189 it('bge-base is 768', () => {
190 assert.strictEqual(
191 embeddingDimension({ provider: 'deepinfra', model: 'BAAI/bge-base-en-v1.5' }),
192 768,
193 );
194 });
195
196 it('bge-small is 384', () => {
197 assert.strictEqual(
198 embeddingDimension({ provider: 'deepinfra', model: 'BAAI/bge-small-en-v1.5' }),
199 384,
200 );
201 });
202
203 it('falls back to 1024 (safe default) for unknown DeepInfra model', () => {
204 assert.strictEqual(
205 embeddingDimension({ provider: 'deepinfra', model: 'some/unknown-model' }),
206 1024,
207 );
208 });
209 });
210
211 describe('formatEmbeddingFetchFailure provider=deepinfra', () => {
212 it('mentions DEEPINFRA_API_KEY, provider env, and re-index requirement', () => {
213 const err = new TypeError('fetch failed');
214 err.cause = new Error('getaddrinfo ENOTFOUND api.deepinfra.com');
215 const s = formatEmbeddingFetchFailure(
216 'deepinfra',
217 'https://api.deepinfra.com/v1/openai/embeddings',
218 'BAAI/bge-large-en-v1.5',
219 err,
220 );
221 assert.match(s, /DeepInfra embeddings unreachable/);
222 assert.match(s, /DEEPINFRA_API_KEY/);
223 assert.match(s, /EMBEDDING_PROVIDER=deepinfra/);
224 assert.match(s, /re-index/);
225 assert.match(s, /BAAI\/bge-large-en-v1\.5/);
226 });
227 });
File History 2 commits
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor 1 day ago
sha256:9103f98c89257ed2b01c237cea895dabb3e85ea337dccb1161c175e4422355b6 docs: accept Calendar Events v0 spec with Phase 0 security … Human 1 day ago